I am new by signalR and Owin and need help.
I wrote all my signalR code in a library [My hub will be self hosted]. Then i referenced that lib from a windows service application, installed the Package "Microsoft.Owin.Host.HttpListener" in the windows service application and tried to execute it.
I am getting that wired exception:
Sequence contains no matching element
I tested my Library in a winForm application and it worked correctly.
I have no idea why i am getting that.
Update: Code example:
In My Library "myLib"
private IDisposable host;
private bool Start()
{
try
{
string url = "http://localhost:5000/";
host = SelfHost.Host(url);
}
catch (Exception ex)
{
log.WriteLine("************HOSTING FAILED ********************************* ex.ToString():"+ ex.ToString()+
" Ex.StackTrace: "+ex.StackTrace +" EX.Message: " + ex.Message + "***************");
}
}
private bool Stop()
{
if (host != null)
{
host.Dispose();
}
}
My SelfHost class:
class SelfHost
{
public static IDisposable Host(string url)
{
return WebApplication.Start<SelfHost>(url);
}
public void Configuration(IAppBuilder app)
{
// Turn cross domain on
var config = new HubConfiguration { EnableCrossDomain = true };
// This will map out to http://localhost:8080/signalr by default
app.MapHubs(config);
}
}
after creating an object from this lib in my windows service application:
myLib l = new myLib();
i implements the OnStart() of the windows Service which starts a thread that calls the Start()-function from myLib:
protected override void OnStart(string[] args)
{
Thread t = new Thread(new ThreadStart(this.StartServiceThread));
t.CurrentCulture = new System.Globalization.CultureInfo("en-US");
t.Start();
}
private void StartServiceThread()
{
l.Start();
}
Output [Ex-Details]
************HOSTING FAILED *********************************
ex.ToString():
System.InvalidOperationException: Sequence contains no matching element
at System.Linq.Enumerable.Single[TSource](IEnumerable`1 source, Func`2 predicate)
at Microsoft.Owin.Hosting.ServerFactory.DefaultServerFactoryLoader.Load(String serverName)
at Microsoft.Owin.Hosting.KatanaEngine.ResolveServerFactory(StartContext context)
at Microsoft.Owin.Hosting.KatanaEngine.Start(StartContext context)
at Microsoft.Owin.Hosting.Starter.DirectHostingStarter.Start(StartOptions options)
at Microsoft.Owin.Hosting.KatanaStarter.Start(StartOptions options)
at Microsoft.Owin.Hosting.WebApplication.Start[TStartup](IServiceProvider services, StartOptions options)
at Microsoft.Owin.Hosting.WebApplication.Start[TStartup](StartOptions options)
at Microsoft.Owin.Hosting.WebApplication.Start[TStartup](String url)
at SelfHost.Host(String url) in SelfHost.cs:line 29
at myLib.Start() in myLib.cs:line 381
Ex.StackTrace:
at System.Linq.Enumerable.Single[TSource](IEnumerable`1 source, Func`2 predicate)
at Microsoft.Owin.Hosting.ServerFactory.DefaultServerFactoryLoader.Load(String serverName)
at Microsoft.Owin.Hosting.KatanaEngine.ResolveServerFactory(StartContext context)
at Microsoft.Owin.Hosting.KatanaEngine.Start(StartContext context)
at Microsoft.Owin.Hosting.Starter.DirectHostingStarter.Start(StartOptions options)
at Microsoft.Owin.Hosting.KatanaStarter.Start(StartOptions options)
at Microsoft.Owin.Hosting.WebApplication.Start[TStartup](IServiceProvider services, StartOptions options)
at Microsoft.Owin.Hosting.WebApplication.Start[TStartup](StartOptions options)
at Microsoft.Owin.Hosting.WebApplication.Start[TStartup](String url)
at SelfHost.Host(String url) in SelfHost.cs:line 29
at myLib.Start() in myLib.cs:line 381
EX.Message: Sequence contains no matching element***************
Thanks in Advance!
I figured out what the problem was. I wrote myLib Code two months ago and was testing it using the winForms Application that i also wrote 2 months ago.
But yesterday i installed the new Owin Packages in my windows service application and tried to use the same library that i wrote before and so i got the error.
The problem is that the NuGetPackage in myLib (old version of Owin.Hosting) is not compatible with the new package version which is released 12 days ago . The new changes do not support WebApplication (from old version). It is called now WebApp.
Related
I'm currently designing an Angular SPA web client, backed with .NET5 REST. It's all in the same Visual Studio project, and it builds / runs fine.
I'm now investigating the possibility of distributing this as a windows desktop application. I was able to get Electron.NET to work, but it seems like a round-about solution (Node?!). I also didn't particularly like that the resources were visible/changeable in the distributed app.
This led me to investigate using WebView2 within WPF (Microsoft seems to be making a similar transition with MSTeams.) I've found some examples, but they only use:
solely remote content ("www.bing.com")
local content, but only img / html / etc
postmessage, etc to communicate using custom objects.
None of these is what I want. Well, that's not entirely true. I need #2 to load the Angular SPA, but when the WebView2-hosted Angular invokes HttpClient, I'd like to intercept that request in the host application and Route it to my REST Controllers. This would allow me to keep nearly all of my code intact, and presumably ship a smaller, more obfuscated exe.
Is this possible? obvious? Is my desire fundamentally flawed? (wouldn't be the first time)
Chromium.AspNetCore.Bridge offers a solution to the problem. It uses owin to host the server-side code in memory, and provides a RequestInterceptor to cleanly relay all requests to the "server" code.
The link above has working examples, but briefly:
App.xaml.cs:
private IWebHost _host;
private AppFunc _appFunc;
public AppFunc AppFunc
{
get { return _appFunc; }
}
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "Development");
_ = Task.Run(async () =>
{
var builder = new WebHostBuilder();
builder.ConfigureServices(services =>
{
var server = new OwinServer();
server.UseOwin(appFunc =>
{
_appFunc = appFunc;
});
services.AddSingleton<IServer>(server);
});
_host = builder
.UseStartup<Startup>()
.UseContentRoot(Directory.GetCurrentDirectory())
.Build();
await _host.RunAsync();
});
}
MainWindow.xaml.cs
private AppFunc _appFunc;
public MainWindow()
{
InitializeComponent();
Browser.CoreWebView2InitializationCompleted += Browser_CoreWebView2InitializationCompleted;
}
private void Browser_CoreWebView2InitializationCompleted(object sender, CoreWebView2InitializationCompletedEventArgs e)
{
if (e.IsSuccess)
{
_appFunc = ((App)Application.Current).AppFunc;
Browser.CoreWebView2.WebResourceRequested += BrowserWebResourceRequestedAsync;
Browser.CoreWebView2.AddWebResourceRequestedFilter("*", CoreWebView2WebResourceContext.All);
}
}
private async void BrowserWebResourceRequestedAsync(object sender, CoreWebView2WebResourceRequestedEventArgs e)
{
var deferral = e.GetDeferral();
var request = new ResourceRequest(e.Request.Uri, e.Request.Method, e.Request.Headers, e.Request.Content);
var response = await RequestInterceptor.ProcessRequest(_appFunc, request);
var coreWebView2 = (CoreWebView2)sender;
e.Response = coreWebView2.Environment.CreateWebResourceResponse(response.Stream, response.StatusCode, response.ReasonPhrase, response.GetHeaderString());
deferral.Complete();
}
I have a VS solution with a "web" project (ASP.NET v5) and a "web.Tests" project (xunit.net 2.1beta) -- one of the tests is checking the rendered pages, and I'm trying to have the test bring up the site automatically, so I don't need to have it running separately/manually.
namespace web.Tests
{
public abstract class BrowserTest : IDisposable
{
protected readonly IisExpress server;
protected readonly IWebDriver driver;
protected BrowserTest()
{
var project = ProjectLocation.FromPath(Path.Combine(SolutionRoot, "src", "web", "wwwroot"));
var app = new WebApplication(project, 8080);
server = new IisExpress(app);
server.Start();
driver = new PhantomJSDriver();
}
public void Dispose()
{
server.Stop();
}
}
}
The server starts and stops fine, but I get an HTTP 500 when I hit a page, with a System.InvalidOperationException:
A type named 'StartupProduction' or 'Startup' could not be found in assembly 'web.Tests'.
How do I specify that I want to run Startup.cs from the "web" project, not the "web.Tests" project?
This was fixed by switching to Kestrel as the host -- especially since Kestrel is now the only supported host in ASP.NET 5
using System;
using System.Diagnostics;
using System.IO;
using OpenQA.Selenium;
using OpenQA.Selenium.PhantomJS;
namespace Test
{
public abstract class PhantomFixture : IDisposable
{
public readonly IWebDriver driver;
private readonly Process server;
protected PhantomFixture()
{
server = Process.Start(new ProcessStartInfo
{
FileName = "dnx.exe",
Arguments = "web",
WorkingDirectory = Path.Combine(Directory.GetCurrentDirectory(), "..", "Web")
});
driver = new PhantomJSDriver();
}
public void Dispose()
{
server.Kill();
driver.Dispose();
}
}
}
(obviously replacing the arguments in Path.Combine(...) with where your web app is located)
After a bit of trail and error with DotNet Core, here is what I came up with. Note that my pathing is a little different to yours as I have my test project separated from my web project.
private System.Diagnostics.Process _WebServerProcess;
[OneTimeSetUp]
public void SetupTest()
{
_WebServerProcess = new System.Diagnostics.Process
{
EnableRaisingEvents = false,
StartInfo = {
WorkingDirectory = Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "..", "..", "..", "MyWebProjectName"),
FileName = $"dotnet.exe",
Arguments = " run"
}
};
}
private void KillWebServer()
{
IEnumerable<Process> processes = Process.GetProcesses()
.Where(p => p.ProcessName == "MyWebProjectName.exe" && p.HasExited == false)
.AsEnumerable();
foreach (Process process in processes)
process.Kill();
if (_WebServerProcess != null)
{
if (!_WebServerProcess.HasExited)
_WebServerProcess.Kill();
_WebServerProcess = null;
}
}
public void Dispose()
{
KillWebServer();
}
Killing both the process that was started (eg, DotNet.exe & the webproject exe) seems be be the trick to ensuring that Kestral stopped.
We have a need to be able to drop new projects/dlls into our main project and have the main project pick them up and be able to use them. It was decided to use AutoFac to handle this need. This way the main project would not need a direct reference to any of the other projects/dlls we want to use. Here is the global.asax:
var builder = new ContainerBuilder();
var directoryName = HttpContext.Current.Server.MapPath("~/bin/");
var cfg = new ModularityLoader(new ModularityConfig(Path.Combine(directoryName, #"Modules")), new Log4NetLogger(typeof(ModularityConfig)));
cfg.RegisterModulesFromCatalog(builder);
builder.RegisterType<AssembliesResolver>().AsImplementedInterfaces();
builder.RegisterType<AppsSecurityFeatureResolver>().AsImplementedInterfaces();
builder.RegisterType<FeaturesAutofacAuthoriztationFilter>()
.AsWebApiAuthorizationFilterFor<ApiController>().InstancePerApiRequest();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterWebApiFilterProvider(GlobalConfiguration.Configuration);
builder.RegisterControllers(typeof(MvcApplication).Assembly);
Container = builder.Build();
We have post-build events on all projects that copy their dlls into the bin directory of our main project. All of the dlls are loaded in here with var cfg = new ModularityLoader.
See image:
builder.Build() calls the following class in any of the dlls in our project that implements Autofac.Module such as this one:
public class AutofacModuleConfig : Autofac.Module
{
protected override void Load(ContainerBuilder builder)
{
base.Load(builder);
builder.RegisterApiControllers(typeof(AutofacModuleConfig).Assembly);
}
}
Here is where the trouble with SignalR comes in. I would like to put RouteTable.Routes.MapHubs() into AutofacModuleConfig, but SignalR 2.0.0+ no longer supports this. Instead, it wants you to create a Startup class like this:
[assembly: OwinStartup("SignalRConfig", typeof(KL.Apps.TestHarness.SignalR.Startup))]
namespace KL.Apps.TestHarness.SignalR
{
public static class Startup
{
public static void Configuration(IAppBuilder app)
{
app.MapSignalR("/signalr", new HubConfiguration());
}
}
}
Note: To get this to work I added the following to the web.config:
<add key="owin:appStartup" value="SignalRConfig" />
SignalR also requires Hub classes like this:
[HubName("BatchHub")]
public class BatchHub : Hub
{
public void RemoveBatchRow(Guid batchId)
{
Clients.All.RemoveBatchRow(batchId);
}
}
Having the Startup class and Hub classes in my main project works perfectly. However, because of the unique nature of AutoFac, none of my Hubs from my external dlls are getting loaded up. I was thinking to try to find a way to force AutofacModuleConfig.Load to accept RouteTable.Routes.MapHubs(), but adding this line breaks the code.
I was thinking to go back to an earlier version of SignalR so I can use RouteTable.Routes.MapHubs() but I would really like to use the most up to date version.
Any ideas?
Thanks in advance.
EDIT 1:
I found this: https://code.google.com/p/autofac/wiki/SignalRIntegration
It seems to be the answer the the problem. However, RegisterHubs does not exist off of the builder object even after installing the Autofac.SignalR NuGet package...
var builder = new ContainerBuilder();
builder.RegisterHubs(Assembly.GetExecutingAssembly());
EDIT 2:
So this is what my AutofacModuleConfig looks like now, but my hubs are still not showing up in javascript.
namespace OurName.IOC
{
public class AutofacModuleConfig : Autofac.Module
{
protected override void Load(ContainerBuilder builder)
{
base.Load(builder);
AutofacSignalRConfig.Load(builder);
builder.RegisterApiControllers(typeof(AutofacModuleConfig).Assembly);
}
}
}
namespace Autofac.Integration.SignalR
{
public static class AutofacSignalRConfig
{
public static void Load(ContainerBuilder builder)
{
builder.RegisterHubs(Assembly.GetExecutingAssembly());
}
}
}
Still not working though. In javascript I cannot see my hubs.
$(document).ready(function(){
var myHub = $.connection.BatchHub;
});
myHub is null.
EDIT 3:
Tried this last night. I removed AutofacSignalRConfig and this is how the main Global.asax looks now:
var builder = new ContainerBuilder();
var directoryName = HttpContext.Current.Server.MapPath("~/bin/");
var cfg = new ModularityLoader(new ModularityConfig(Path.Combine(directoryName, #"Modules")), new Log4NetLogger(typeof(ModularityConfig)));
cfg.RegisterModulesFromCatalog(builder);
builder.RegisterType<AssembliesResolver>().AsImplementedInterfaces();
builder.RegisterType<AppsSecurityFeatureResolver>().AsImplementedInterfaces();
builder.RegisterType<FeaturesAutofacAuthoriztationFilter>()
.AsWebApiAuthorizationFilterFor<ApiController>().InstancePerApiRequest();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterWebApiFilterProvider(GlobalConfiguration.Configuration);
builder.RegisterControllers(typeof(MvcApplication).Assembly);
foreach (var assembly in cfg.LoadedAssemblies)
{
var hubs = builder.RegisterHubs(assembly);
}
Container = builder.Build();
GlobalHost.DependencyResolver = new Autofac.Integration.SignalR.AutofacDependencyResolver(Container);
Notice how I tried to take the output of cfg (which is a collection of all assemblies found in the bin folder) and then foreach through them in order to execute builder.RegisterHubs on each one. Still not picking up my hubs from any of those assemblies though.
Does there need to be a Startup class in each of my imported dlls too? If so, how would I go about calling it?
EDIT 4:
Tried this too with no success:
foreach (var assembly in cfg.LoadedAssemblies)
{
//var hubs = builder.RegisterHubs(assembly);
var a = assembly.GetExportedTypes().Where(x => x.BaseType == typeof (Hub));
foreach (var x in a)
{
builder.RegisterType(x);
}
}
See image for debug info:
EDIT 5:
Jim Bolla thank you for the input. Here is my first try at your suggestion.
public class AssemblyLocator : IAssemblyLocator
{
public IList<Assembly> GetAssemblies()
{
var directoryName = HttpContext.Current.Server.MapPath("~/bin/");
var cfg = new ModularityLoader(new ModularityConfig(Path.Combine(directoryName, #"Modules")), new Log4NetLogger(typeof(ModularityConfig)));
return cfg.LoadedAssemblies;
}
}
Also added this just above Container = builder.Build:
builder.RegisterType<AssemblyLocator>().As<IAssemblyLocator>().SingleInstance();
AssemblyLocator.GetAssemblies() is now getting called.
... Testing ...
EDIT 6:
Okay. So now when I throw a breakpoint into javascript, I can see $.connection.BatchHub which is great! However, when trying to call the hub method RemoveBatchRow on the server-side I get the following error:
"Using a Hub instance not created by the HubPipeline is unsupported."
Here is the stack trace:
at
Microsoft.AspNet.SignalR.Hubs.NullClientProxy.TryInvokeMember(InvokeMemberBinder
binder, Object[] args, Object& result) at CallSite.Target(Closure ,
CallSite , Object , Guid ) at
System.Dynamic.UpdateDelegates.UpdateAndExecuteVoid2[T0,T1](CallSite
site, T0 arg0, T1 arg1) at
KL.Apps.WebIndex.Hubs.BatchHub.RemoveBatchRow(Guid batchId) in
d:\Source\Apps Framework
Modules\WebIndex\Main\Source\KL.Apps.WebIndex\Hubs\BatchHub.cs:line 20
at
KL.Apps.WebIndex.API.Batch.BatchLockController.TryLockBatchAsync(String
batchId) in d:\Source\Apps Framework
Modules\WebIndex\Main\Source\KL.Apps.WebIndex\API\Batch\BatchLockController.cs:line
30 at lambda_method(Closure , Object , Object[] ) at
System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass13.b__c(Object
instance, Object[] methodParameters) at
System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object
instance, Object[] arguments) at
System.Web.Http.Controllers.ReflectedHttpActionDescriptor.<>c__DisplayClass5.b__4()
at System.Threading.Tasks.TaskHelpers.RunSynchronously[TResult](Func`1
func, CancellationToken cancellationToken)
I am calling the hub method from one of my remote dlls like this:
new BatchHub().RemoveBatchRow(gId);
You can see the definition for BatchHub above.
Any other ideas?
I'm face a problem since few days and I can't get solution. below is my app structure:
I have ejbapp.jar inside MyearDeployedOnJboss7.ear at the same level of equinox-server-side-app.war (built using warproduct) and I want to load class from MyJarToLaoadForEjbapp.jar which is in iModernizeWebClient_1.0.0.jar which is in plugins folder of equinox-server-side-app.war (I want show image of app structure but I cannot send image because forum rules need 10 score to be able to do that)
My question is how to allow ejbapp.jar load classes from "MyJarToLaoadForEjbapp.jar" inside MyWebClient_1.0.0.jar's plugin folder which is in the equinox-server-side-app.war.
I think using servletbridge classloader but no idea how to use it.
in my launch.ini I've:
osgi.*=#null org.osgi.*=#null eclipse.*=#null osgi.parentClassloader=app osgi.contextClassLoaderParent=app
I resolved my proble using Servlet HttpServiceTracker from the OSGI spec. how to do it : write HttpServiceTracker liket that :
public class HttpServiceTracker extends ServiceTracker {
private static final Logger logger = Logger
.getLogger(HttpServiceTracker.class.getName());
public HttpServiceTracker(BundleContext context) {
super(context, HttpService.class.getName(), null);
}
public Object addingService(ServiceReference reference) {
HttpService httpService = (HttpService) context.getService(reference);
logger.info("default context path : "
+ org.eclipse.rap.ui.internal.servlet.HttpServiceTracker.ID_HTTP_CONTEXT);
try {
logger.info("will register servlet ");
httpService.registerServlet("/programLauncherServlet",
new ProgramLauncherServlet(), null, null);
logger.info("servlet has been registred with http context ");
// httpService.registerResources( "/", "/html", null );
} catch (Exception e) {
//e.printStackTrace();
logger.info("The alias '/programLauncherServlet' is already in use");
}
return httpService;
}
public void removedService(ServiceReference reference, Object service) {
logger.info("will unregister servlet ");
HttpService httpService = (HttpService) service;
httpService.unregister("/programLauncher");
super.removedService(reference, service);
logger.info("servlet has been unregistred");
}
in your plugin activator class at method start :
#Override
public void start(BundleContext context) throws Exception {
super.start(context);
Activator.plugin = this;
BundleContext osgiContext = BundleReference.class
.cast(AnyClassOfYourProject.class.getClassLoader()).getBundle()
.getBundleContext();
serviceTracker = new HttpServiceTracker(osgiContext);
serviceTracker.open();
LOGGER.info("servlet published !!");
LOGGER.info("Bundle started.");
}
and for unregister the servlet at the stop method :
public void stop(BundleContext context) throws Exception {
Activator.plugin = null;
serviceTracker.close();
serviceTracker = null;
LOGGER.info("servlet unregistered from context !!");
super.stop(context);
}
that's all. your servlet is accessible outside your eclipse bundle and you can call methods inside the bundle.
I'm starting a web application that contains the following projects:
Booking.Web
Booking.Services
Booking.DataObjects
Booking.Data
I'm using the repository pattern in my data project only. All services will be the same, no matter what happens. However, if a customer wants to use Access, it will use a different data repository than if the customer wants to use SQL Server.
I have StructureMap, and want to be able to do the following:
Web project is unaffected. It's a web forms application that will only know about the services project and the dataobjects project.
When a service is called, it will use StructureMap (by looking up the bootstrapper.cs file) to see which data repository to use.
An example of a services class is the error logging class:
public class ErrorLog : IErrorLog
{
ILogging logger;
public ErrorLog()
{
}
public ErrorLog(ILogging logger)
{
this.logger = logger;
}
public void AddToLog(string errorMessage)
{
try
{
AddToDatabaseLog(errorMessage);
}
catch (Exception ex)
{
AddToFileLog(ex.Message);
}
finally
{
AddToFileLog(errorMessage);
}
}
private void AddToDatabaseLog(string errorMessage)
{
ErrorObject error =
new ErrorObject
{
ErrorDateTime = DateTime.Now,
ErrorMessage = errorMessage
};
logger.Insert(error);
}
private void AddToFileLog(string errorMessage)
{
// TODO: Take this value from the web.config instead of hard coding it
TextWriter writer = new StreamWriter(#"E:\Work\Booking\Booking\Booking.Web\Logs\ErrorLog.txt", true);
writer.WriteLine(DateTime.Now.ToString() + " ---------- " + errorMessage);
writer.Close();
}
}
I want to be able to call this service from my web project, without defining which repository to use for the data access. My boostrapper.cs file in the services project is defined as:
public class Bootstrapper
{
public static void ConfigureStructureMap()
{
ObjectFactory.Initialize(x =>
{
x.AddRegistry(new ServiceRegistry());
}
);
}
public class ServiceRegistry : Registry
{
protected override void configure()
{
ForRequestedType<IErrorLog>().TheDefaultIsConcreteType<Booking.Services.Logging.ErrorLog>();
ForRequestedType<ILogging>().TheDefaultIsConcreteType<SqlServerLoggingProvider>();
}
}
}
What else do I need to get this to work? When I defined a test, the ILogger object was null.
Perhaps some details on how you are calling this code from a test would be useful.
My understanding is that you need to ensure that the ConfigureStructureMap call has been made early in the applications life (e.g. in the Global.asax in a web project).
After that you would be calling for instances of IErrorLog using something like:
IErrorLog log = StructureMap.ObjectFactory.GetNamedInstance<IErrorLog>();