signalr self-host and static file server (e.g. owin.selfhost) - signalr

I have been "too" succesfully with my stand-alone Singular web service. We would like to now remove the IIS server, which does little other than serve about 10 JS/HTML/CSS files. Node.JS has a static-files plugin,
I looked and I saw that Katana, OWIN.SelfHost also has such a feature.
http://odetocode.com/blogs/scott/archive/2014/02/10/building-a-simple-file-server-with-owin-and-katana.aspx
Update
It was suggested to use the OWIN.Self-Host which has a feature, but I am unsure of where to put it in my existing code, and if it would effect the existing SIGNALR code (all Hubs share the same HTTP request calls, so I am also squeezing in Self-host on the same port, I wonder if that works). As well as it would be nice to use Scott Allen's (above referenced) example which also allows File Browsing.
Here is the code I current use to start up SIGNALR (V2.2) , which is run at the directly from the Main.cs file:
class Comm
{
public string url = "http://localhost:7700";
// string url = "http://*:7700"; // Requires admin privileges
public void start()
{
Task t = Task.Run(() =>
{
WebApp.Start<Startup>(url);
this.Clients = GlobalHost.ConnectionManager.GetHubContext<GatewayHub>().Clients;
Console.WriteLine("Server running on {0}", url);
Thread.Sleep(Timeout.Infinite);
});
}
public void send()
{
Clients.All.display("broadcast sent...");
}
private IHubConnectionContext<dynamic> Clients
{
get;
set;
}
}
class Startup
{
public void Configuration(IAppBuilder app)
{
var hubConfiguration = new HubConfiguration();
hubConfiguration.EnableDetailedErrors = (Tools.LogLevel >= 12);
hubConfiguration.EnableJavaScriptProxies = true;
app.UseCors(CorsOptions.AllowAll);
app.MapSignalR("/signalr", hubConfiguration);
}
}

This answer is really from #Tracther, and I wish he would write it up so that I can credit him. But thanks to his input, here is what works for me. I did not need the commented lines. All I needed was to set the paths for /signlar and for the static FileSystem
}
class Startup
{
public void Configuration(IAppBuilder app)
{
var hubConfiguration = new HubConfiguration();
hubConfiguration.EnableDetailedErrors = (Tools.DebugLevel > 12);
hubConfiguration.EnableJavaScriptProxies = true;
app.UseCors(CorsOptions.AllowAll);
//app.UseStaticFiles();
app.UseFileServer(new FileServerOptions()
{
//RequestPath = new PathString("/Scopes"),
EnableDirectoryBrowsing = true,
FileSystem = new PhysicalFileSystem(#".\Scopes"),
});
app.MapSignalR("/signalr", hubConfiguration);
}
}

Related

Best way to pass configuration to Topshelf.HostFactory.Run in .Net core

I'm trying to develop/convert current .Net framework code of Task Consumer to Top shelf and .NET core 3.1 . I want to read the config data from json file and use those in start as well as in consume methods.
What is the best and simplest way to pass config data to Task Consumer service and other end points
Any suggestion/comments are helpful.
Thanks in advance .
My current code is
static void Main(string[] args)
{
var configuration = new ConfigurationBuilder().AddJsonFile("appsettings.json", true,true).Build();
var test2 = configuration.GetSection("RabbitMQSettings");
Console.WriteLine(HostFactory.Run(cfg => cfg.Service<TaskConsumerService>()));
}
ConsumerService code
public class TaskConsumerService : ServiceControl
{
IBusControl _bus;
IConfiguration _configuration;
public bool Start(HostControl hostControl)
{
_bus = ConfigureBus();
_bus.Start();
return true;
}
public bool Stop(HostControl hostControl)
{
_bus?.Stop(TimeSpan.FromSeconds(30));
return true;
}
IBusControl ConfigureBus()
{
return Bus.Factory.CreateUsingRabbitMq(cfg =>
{
var rabbitMQUrl = ConfigurationManager.AppSettings["RabbitMQSettings:RabbitMQHostUrl"];
cfg.Host(new Uri(rabbitMQUrl) , h =>
{
h.Username(ConfigurationManager.AppSettings["RabbitMQSettings:username"]);
h.Password(ConfigurationManager.AppSettings["RabbitMQSettings:pwd"]);
});
var queue0 = ConfigurationManager.AppSettings["QueName"];
cfg.ReceiveEndpoint(queue0 , e =>
{
e.Consumer<TransformConsumer>();
});
});
}
}
Consumer code
public class TransformConsumer : IConsumer<IExecuteTransform>
{
private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
string address = string.Empty;
const string json = "application/json";
public async Task Consume(ConsumeContext<IExecuteTransform> context)
{
m_log.Info(" Transform started.");
// Processing
try
{
address = string.Concat(ConfigurationManager.AppSettings["RabbitMQSettings:RabbitMQHost"] , ConfigurationManager.AppSettings["RabbitMQSettings:queName"]);
IExecuteTransform message = await ConsumeSendEndPoint(context , address);
m_log.Info(" Transform Process completed.");
}
catch ( Exception e )
{
m_log.Error("Transform failed");
throw e;
}
}
}
I'd recommend moving from Topshelf to the .NET Core Generic Host, which is used in the console service sample. It uses the standard .NET Core extension packages for configuration, dependency injection, etc.

Publish on .NET Core 2.2 SignalR Hub as EXE not working on Self-Host but works in Visual Studio

I have a Hub that works inside Visual Studio Community 2017 for ASP.Net Core & SignalR. Everything works beautifully as long as it runs under VS. I read what is available & am not getting any luck. I have a HostedService that on StartAsync kicks off a thread with the Background prop set to true. This thread reads from a socket & then calls SendMessage on the Hub. I'm not sure what I'm doing wrong. It publishes an exe, but it is not working.
I have read all that I can find. I added a Hosted Service that is added under Startup.
// STARTUP
public class cRioHubStartup {
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddSignalR();
services.AddMvc();
services.AddHostedService<cRioHubHostService>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
string virtDir = cRioHubGlobals.getHubUrl().VirtualDirectory;
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
//app.UseHsts();
}
app.UseDefaultFiles();
app.UseStaticFiles();
//app.UseCors(CorsOptions.AllowAll);
app.UseSignalR(routes =>
{
routes.MapHub<cRioHub>(virtDir);
});
app.UseMvc();
app.Run(async (context) =>
{
await context.Response.WriteAsync("cRioHub Started!");
});
}
/*
var hubContext = provider.GetService<IHubContext<cRioHub>>();
services.AddSingleton(provider =>
{
var hubContext = provider.GetService<IHubContext<cRioHub>>();
var update = new Update(hubContext);
return update;
});
*/
}
// HUB HOSTED SERVICE which kicks off background thread
public class cRioHubHostService : IHostedService, IDisposable
{
private static Thread _t = null;
public Thread thread
{
get { return _t; }
}
// Summary: Triggered when the application host is ready to start the service.
public Task StartAsync(CancellationToken cancellationToken)
{
_t = LaunchHub();
return Task.CompletedTask;
}
// Summary: Triggered when the application host is performing a graceful shutdown.
public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
public void Dispose()
{
_t = null;
}
public static Thread LaunchHub()
{
Object orfu = new object(); // saved for fut. use if needed
// set up hub
cRioHubConnection hub = new cRioHubConnection(cRioHubGlobals.getHubUrl(), cRioHubGlobals.getHubUrl().Name);
cRioHubGlobals.setHubConnection(new cRioHubConnection(hub));
//Globals.HubCnxn.SendMessage("Take2!");
// call thread to start TCP client wh. writes back to the hub on cRio msg. arrival
Thread t = new Thread(cRioHubTcpClient.cRioRunClient);
t.IsBackground = true;
t.Start(orfu);
return t;
}
public static void cRioRunClient(Object orfu)
{
string consMsg = "";
string urlHub = cRioHubGlobals.getHubUrl().makeUrl();
string urlCRio = cRioHubGlobals.getCRioUrl().makeUrl();
string fmtHubUrl = "Hub URL={0}" ;
string fmtCRioUrl = "cRio URL={0}";
consMsg = String.Format(fmtHubUrl, urlHub);
Console.WriteLine(consMsg);
consMsg = String.Format(fmtCRioUrl, urlCRio);
Console.WriteLine(consMsg);
cRioHubGlobals.setCRioTcpClient(new cRioHubTcpClient(orfu)); // gets its connection info from cRioHubGlobals
cRioHubGlobals.getCRioTcpClient().Message += (s, a) => Console.WriteLine("Client: " + a.Message);
Task clientTask = cRioHubGlobals.getCRioTcpClient().RunAsync();
Console.WriteLine("Program: Hit any char to stop.");
ConsoleEx.ReadChar();
cRioHubGlobals.getCRioTcpClient().Stop = true;
cRioHubGlobals.getCRioTcpClient().Dispose();
clientTask = null;
}
public static Task cRioStopClient()
{
Task tskHub = null;
cRioHubTcpClient client = cRioHubGlobals.getCRioTcpClient();
if (client != null)
{
client.Stop = true;
client.Dispose();
tskHub = cRioHubGlobals.getHubConnection().Stop();
}
Console.WriteLine("Stopping service!");
return tskHub;
}
The problem is the publisher with the appsettings & launch. If you choose a port other than the default 5000, it is not working. If you choose 5000, it works. This appears to be a bug.

Getting 401 Error with SignalR Owin Host 2.0.3

I am trying to setup a load test exercising as much of the code base as possible. I am running the server and client in the same process:
class Program
{
class Startup
{
public void Configuration(IAppBuilder app)
{
app.MapSignalR(new HubConfiguration
{
EnableDetailedErrors = true
});
}
}
public static void Main(string[] args)
{
var signalr = "http://localhost:21337/";
using (WebApp.Start<Startup>(signalr))
{
var connection = new HubConnection(signalr) {Credentials = CredentialCache.DefaultNetworkCredentials};
var catalog = connection.CreateHubProxy("CatalogHub");
connection.Start().Wait();
catalog.Invoke("SendChat", String.Empty, String.Empty, String.Empty);
Console.ReadLine();
}
}
}
However, on connection.Start.Wait() I get a 401 Unauthorized error. I am not sure why because IIS is nowhere in the pipeline.
PEBKAC. Turns out the hub has [Authorize] set on it but I was using anonymous authentication. Ensuring Ntlm authentication fixed the problem.
public class Startup
{
public void Configuration(IAppBuilder app)
{
var listener = (HttpListener)app.Properties[typeof(HttpListener).FullName];
listener.AuthenticationSchemes = AuthenticationSchemes.Ntlm;
app.MapSignalR(new HubConfiguration
{
EnableDetailedErrors = true,
EnableJSONP = true
});
}
}
I was getting the same error after I set the Authorize attribute on my hub class and found out that Windows Authentication was disabled in the properties for my Web API project. This was pointed out in getting 401 error with signalr owin host 2.0.3. This worked perfectly when I enabled it and I was also able to get the User Identity Name in my hub
One thing to note is that I did not have to set the Authentication scheme as mentioned in the above post

Configuring WCF Services in Code WCF 4.5

Hi, I am trying to configure wcf using code behind, below is the code:
public static void Configure(ServiceConfiguration config)
{
string configPath = ConfigurationManager.AppSettings["wcfconfigDBPath"];
// Enable “Add Service Reference” support
config.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = true });
// set up support for http, https, net.tcp, net.pipe
if (isEnabled(configPath, "enablehttp"))
config.EnableProtocol(new BasicHttpBinding());
if (isEnabled(configPath, "enablenettcp"))
config.EnableProtocol(new NetTcpBinding());
if (isEnabled(configPath, "enablepipe"))
config.EnableProtocol(new NetNamedPipeBinding());
}
private static bool isEnabled(string path, string elementName)
{
try
{
string elementValue = string.Empty;
bool returnVal = false;
using (XmlTextReader reader = new XmlTextReader(path))
{
reader.ReadToFollowing(elementName);
if (reader.Read())
elementValue = reader.Value;
}
if (!string.IsNullOrEmpty(elementValue))
{
bool.TryParse(elementValue, out returnVal);
}
return returnVal;
}
catch (Exception ex)
{
return false;
}
}
The above code is not working. I am not sure when the "static void Configure" gets fired.
My question is, is there any way to enable/disable the protocol based on DB/xml configuration without bringing down the service?
New feature in .NET 4.5 which probably can be used in your case:
Note: The configure method is called by WCF before the service host is opened.
The Configure method takes a ServiceConfiguration instance that enables the developer to add endpoints and behaviors. This method is called by WCF before the service host is opened. When defined, any service configuration settings specified in an app.config or web.config file will be ignored.
The following code snippet illustrates how to define the Configure method and add a service endpoint, an endpoint behavior and service behaviors:
public class Service1 : IService1
{
public static void Configure(ServiceConfiguration config)
{
ServiceEndpoint se = new ServiceEndpoint(new ContractDescription("IService1"), new BasicHttpBinding(), new EndpointAddress("basic"));
se.Behaviors.Add(new MyEndpointBehavior());
config.AddServiceEndpoint(se);
config.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = true });
config.Description.Behaviors.Add(new ServiceDebugBehavior { IncludeExceptionDetailInFaults = true });
}
public string GetData(int value)
{
return string.Format("You entered: {0}", value);
}
public CompositeType GetDataUsingDataContract(CompositeType composite)
{
if (composite == null)
{
throw new ArgumentNullException("composite");
}
if (composite.BoolValue)
{
composite.StringValue += "Suffix";
}
return composite;
}
}
Refer for complete example to:https://msdn.microsoft.com/en-us/library/hh205277(v=vs.110).aspx

SignalR: How to call .Net client method from server?

I want to send data to my console application wich have a connection to my "someHub". I tried to do as described in example from a link but got no result.
Server side code:
[HubName("somehub")]
public class SomeHub : Hub
{
public override Task OnConnected()
{
//Here I want to send "hello" on my sonsole application
Clients.Caller.sendSomeData("hello");
return base.OnConnected();
}
}
Clien side code:
public class Provider
{
protected HubConnection Connection;
private IHubProxy _someHub;
public Provider()
{
Connection = new HubConnection("http://localhost:4702/");
_someHub = Connection.CreateHubProxy("somehub");
Init();
}
private void Init()
{
_someHub.On<string>("sendSomeData", s =>
{
//This code is not reachable
Console.WriteLine("Some data from server({0})", s);
});
Connection.Start().Wait();
}
}
What is the best solution for implementing this and what is the reason why i am not able to invoke the client method?
Are you trying to talk to clients outside of Hub? If yes then you will have to get a HubContext outside of Hub. And then you can talk all the clients.
IHubContext context = GlobalHost.ConnectionManager.GetHubContext<MyHub>();
SignalR Server using Owin Self Host
class Program
{
static void Main(string[] args)
{
string url = "http://localhost:8081/";
using (WebApplication.Start<Startup>(url))
{
Console.WriteLine("Server running on {0}", url);
Console.ReadLine();
IHubContext context = GlobalHost.ConnectionManager.GetHubContext<MyHub>();
for (int i = 0; i < 100; i++)
{
System.Threading.Thread.Sleep(3000);
context.Clients.All.addMessage("Current integer value : " + i.ToString());
}
Console.ReadLine();
}
}
}
class Startup
{
public void Configuration(IAppBuilder app)
{
// Turn cross domain on
var config = new HubConfiguration { EnableCrossDomain = true };
config.EnableJavaScriptProxies = true;
// This will map out to http://localhost:8081/signalr by default
app.MapHubs(config);
}
}
[HubName("MyHub")]
public class MyHub : Hub
{
public void Chatter(string message)
{
Clients.All.addMessage(message);
}
}
Signalr Client Console Application consuming Signalr Hubs.
class Program
{
static void Main(string[] args)
{
var connection = new HubConnection("http://localhost:8081/");
var myHub = connection.CreateHubProxy("MyHub");
connection.Start().Wait();
// Static type
myHub.On<string>("addMessage", myString =>
{
Console.WriteLine("This is client getting messages from server :{0}", myString);
});
myHub.Invoke("Chatter",System.DateTime.Now.ToString()).Wait();
Console.Read();
}
}
To run this code, create two separate applications, then first run server application and then client console application, then just hit key on server console and it will start sending messages to the client.

Resources