I have a simple SingulaR example that I've added to a legacy ASP.Net MVC application.
Here are the various parts:
OWIN Startup class
[assembly: OwinStartup(typeof (Startup))]
namespace MyApp.Web
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.MapSignalR();
}
}
}
SignalR Hub
using System.Collections.Generic;
using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Hubs;
namespace MyApp.Web
{
[HubName("podService")]
public class PodServiceHub : Hub
{
public PodServiceHub()
{
;
}
public IEnumerable<string> GetMessages()
{
return new[] {"blah", "blah", "blah"};
}
}
}
Server-side facade
using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Hubs;
namespace MyApp.Web
{
public class PodService
{
PodService(IHubConnectionContext<dynamic> clients)
{
Clients = clients;
}
public PodService()
: this(GlobalHost.ConnectionManager.GetHubContext<PodServiceHub>().Clients)
{
}
IHubConnectionContext<dynamic> Clients { get; set; }
public void SendMessageToClient(string message)
{
Clients.All.doSomething(message);
}
}
}
Portions of startup Javascript:
var podService = $.connection.podService;
...
$.extend(podService.client, {
doSomething: function(message) {
console.log("received message:" + message);
}
});
// test
$.connection.hub.start()
.done(function() {
podService.server.getMessages()
.done(function(messages) {
console.log("received message:" + message);
});
});
Within one of the controllers called by the first page:
_podService.SendMessageToClient("Hello from the server!");
Upon executing the application, the following error is displayed in the console of Chrome's dev tools:
WebSocket connection to 'ws://localhost:62025/signalr/connect?transport=webSockets&clientProtocol=1.5&connectionToken=02LJFqBcRBWKXAOlaSwgMPWG0epV7AFl19gNjFCvA0dxD2QH8%2BC9V028Ehu8fYAFN%2FthPv65JZKfK2MgCEdihCJ0A2dMyENOcdPkhDzEwNB2WQ1X4QXe1fiZAyMbkZ1b&connectionData=%5B%7B%22name%22%3A%22podservice%22%7D%5D&tid=6' failed: Error during WebSocket handshake: net::ERR_CONNECTION_RESET
After this error, however, the podService.server.getMessages() returns with the message from the server printing ["blah", "blah", "blah"] to the console and subsequently the doSomething client function is invoked printing "received message: Hello from the server!".
The calls from both the client and the server are transmitting data, so this error doesn't appear to be breaking the app. It definitely seems to be an issue though. The code above was based upon the sample code generated by the Microsoft.AspNet.SignalR.Sample NuGet package which doesn't display the same behavior. The only difference I'm aware of between my example and NuGet-based sample is that I've added this to a legacy MVC app vs. a pure OWIN-based app. Based upon a comment I read on this SO question this shouldn't be an issue.
So, what's wrong with this example usage and/or what could be causing the connection reset?
I made sure:
the web socket component is enabled in IIS
and the "allowKeepAlive" setting is not set to false in my web.config
But in my case the problem was caused by a packages version mismatch:
In the packages.config Microsoft.Owin.Host.SystemWeb version 2.1.0 was referenced accidentally
<package id="Microsoft.Owin.Host.SystemWeb" version="2.1.0" targetFramework="net452" />
While all the other Owin related packages were referencing version 3.0.1
I updated Microsoft.Owin.Host.SystemWeb to version 3.0.1
Then I had to make sure in the web.config file the "httpRuntime" element targeted the framework version 4.5
<system.web>
<httpRuntime targetFramework="4.5" />
</system.web>
The two steps above solved the problem.
Just ran in to this one myself. In my case the answer seems to be enabling WebSockets for IIS.
Enable WebSockets in IIS 8.0
It works because signalR falls back to one of the following depending on the capabilities of the browser and server.
Server Sent Events.
Forever Frame
AJAX Long Polling
For more information on the transports used and their fallbacks see here
In my case, I had to remove
<httpProtocol allowKeepAlive="false" />
from our web.config (it was there for historical reasons).
In my Case I was using
string sqlConnectionString = ConfigurationManager.ConnectionStrings["GAFI_SignalR"].ConnectionString;
GlobalHost.DependencyResolver.UseSqlServer(sqlConnectionString);
The problem was accessing the database when the user didin't have permission to connect to the database.
Related
We deployed on a existing server that was already setup and configured with another asp.net application. This isn't something we normally do, as we setup on a new server and configure everything. We also have this same ASP.NET application running on several other servers with no problems.
The application is MVC3 running on ASP.NET 4
The app uses controllers to create a simple RPC type of API.
Example: (Send) /Services/LMS/GetCourses (Returns) XML document
Once we deployed the asp.net application and had everything setup in IIS we ran into an issue we never seen before.
The application will send a NullReferenceException on the line below.
DbProviderFactories.GetFactory(ConfigurationManager.ConnectionStrings["LMS"].ProviderName);
But only if the http request is a POST. If we send a GET request, it works.
I guessing this is some configuration conflict. Is there something in a config file that could limit our application from reading our Web.config settings on a POST?
To provide more context based on comments:
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Configuration;
using Services.Models;
public class DBConnection
{
protected DbProviderFactory factory;
protected string connectionString;
protected char paramChar; // could be ':' or '#' depending on database
public DBConnection(string db) // db is equal to "LMS"
{
try
{
factory = DbProviderFactories.GetFactory(ConfigurationManager.ConnectionStrings[db].ProviderName); // the exception stack points to this line having NullReferenceException
connectionString = ConfigurationManager.ConnectionStrings[db].ConnectionString;
paramChar = DbUtil.GetParamChar(ConfigurationManager.ConnectionStrings[db].ProviderName);
}
catch (ConfigurationErrorsException)
{
throw new ConfigurationErrorsException("The database " + db + " has not been defined in the web.config file.");
}
}
}
I wanwt to add a layer of security via certificate to access a hosted ASP.NET WebAPI.
I want only those clients who have installed the certificate in their machine to have access to that WebAPI.
Can anyone provide me a way to achieve this behavior?
You can configure IIS to require client certificates without writing a single line of code. Just follow these instructions, specifically these:
Click SSL settings in the middle panel and select Require SSL and Require for Client certificates.
Double click the Authentication icon and disable all the Authentication method.
Make sure the IIS Client Certificate Mapping Authentication is installed.
Click the Configuration Editor in the middle panel and set the one to one mappings refer to this link
Just as suggested in comments, a quick google search could lead to interesting results.
Nevertheless a possible solution is the implementation proposed in the following Microsoft article :
public class RequireHttpsAttribute : AuthorizationFilterAttribute
{
public override void OnAuthorization(HttpActionContext actionContext)
{
if (actionContext.Request.RequestUri.Scheme != Uri.UriSchemeHttps)
{
actionContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden)
{
ReasonPhrase = "HTTPS Required"
};
}
else
{
base.OnAuthorization(actionContext);
}
}
}
You would then decorate your ApiController action :
public class SomeController : ApiController
{
[RequireHttps]
public HttpResponseMessage Get() { ... }
}
I am developing a real time application based on signal R . I am using .NET framework 4 , Signal R version 1.2.2 in VS 2010.I am getting a Hub reference error stating
Uncaught Error: SignalR: Error loading hubs. Ensure your hubs reference is correct, e.g. <script src='/signalr/hubs'></script>.
I got a solution to add the Hub reference in global file. But since i am using DNN framework it contains multiple projects and have a common global file.
RouteTable.Routes.MapHubs("/myhubs", new HubConfiguration());
i tried adding this piece of code there, but it too didn't works..
my hub class
public class ChatHub : Hub
{
public void Send(string message)
{
Clients.Others.receive(message);
}
}
And start up class is
[assembly: OwinStartup(typeof(DotNetNuke.Modules.VideoChat.Startup))]
namespace DotNetNuke.Modules.VideoChat
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.MapHubs();
}
}
}
i am using jquery on client side.
var chat = $.connection.chatHub;
$.connection.hub.start().done(function () {}
Can anyone suggest a way around
You need to follow these steps:
Create a Hub class on the server that inherits the Hub class from SignalR
Create client proxy for the Hub class (using .NET class or javascript code)
Startup the Hub on the server using MapHubs() (obsolete)
Your question does not give enought information. Is it a web application? Are you using javascript or .NET on the client side?
See this post: SignalR hubclass in classlibrary
EDIT
Here is what you should have in your Startup class now that I see that you are using OWIN:
[assembly: OwinStartup("StartupConfiguration", typeof(DotNetNuke.Modules.VideoChat.Startup))]
namespace DotNetNuke.Modules.VideoChat
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
// SignalR Hub Startup
var hubConfiguration = new HubConfiguration();
hubConfiguration.EnableDetailedErrors = true;
hubConfiguration.EnableJavaScriptProxies = true;
hubConfiguration.EnableJSONP = false;
app.MapSignalR(hubConfiguration);
}
}
}
In your web.config, add these lines:
<appSettings>
<add key="owin:appStartup" value="StartupConfiguration" />
<add key="owin:AutomaticAppStartup " value="true" />
</appSettings>
I've developed a sample SignalR application based on ASP.NET 4.5 & Owin, and I've hosted that app on IIS 7.5.
Everything is working fine, but how can I handle exceptions in Owin?
Consider the following code:
[HubName("SampleHub")]
public class SampleHub : Hub
{
public SampleHub()
{
throw new InvalidOperationException("?!");
}
}
This exception won't call Application_Error (and this is my problem).
Where can I get all exceptions from Owin for logging and debugging purposes similarly to Application_Error?
I'm not interested in something like this:
app.UseErrorPage(new ErrorPageOptions()
{
ShowCookies = true,
ShowEnvironment = true,
ShowExceptionDetails = true,
ShowHeaders = true,
ShowQuery = true,
ShowSourceCode = true
});
This is totally useless for advanced scenarios, something like ASP.NET Web API and ASP.NET MVC.
Action filters with OnException method for override purposes is much better.
If you want exception handling specifically for SignalR Hubs, OWIN middleware is not the way to go.
To illustrate just one reason why, suppose that SignalR is using its WebSocket transport when an exception is thrown from inside a Hub method. In this case, SignalR will not close the WebSocket connection. Instead SignalR will write a JSON encoded message directly to the socket to indicate to the client that an exception was thrown. There is no easy way using OWIN middleware to trigger any sort of event when this happens outside of possibly wrapping the entire OWIN WebSocket Extension which I would strongly advise against.
Fortunately SignalR provides its own Hub Pipeline which is perfectly suited for your scenario.
using System;
using System.Diagnostics;
using Microsoft.AspNet.SignalR.Hubs;
public class MyErrorModule : HubPipelineModule
{
protected override void OnIncomingError(ExceptionContext exceptionContext, IHubIncomingInvokerContext invokerContext)
{
MethodDescriptor method = invokerContext.MethodDescriptor;
Debug.WriteLine("{0}.{1}({2}) threw the following uncaught exception: {3}",
method.Hub.Name,
method.Name,
String.Join(", ", invokerContext.Args),
exceptionContext.Error);
}
}
You can use the ExceptionContext for more than just logging. For example you can set ExceptionContext.Error to a different exception which will change the exception the client receives.
You can even suppress the exception by setting ExceptionContext.Error to null or by setting ExceptonContext.Result. If you do this, It will appear to the client that the Hub method returned the value you found in ExceptonContext.Result instead of throwing.
A while back a wrote another SO answer about how you can call a single client callback for every exception thrown by a Hub method: SignalR exception logging?
There is also MSDN documentation for HubPipelineModules: http://msdn.microsoft.com/en-us/library/microsoft.aspnet.signalr.hubs.hubpipelinemodule(v=vs.118).aspx
The answer by #halter73 is great for errors thrown inside hubs, but it doesn't catch errors thrown during their creation.
I was getting the exception:
System.InvalidOperationException: 'foobarhub' Hub could not be resolved.
The server was returning an HTML page for this exception, but I needed it in JSON format for better integration with my Angular app, so based on this answer I implemented an OwinMiddleware to catch exceptions and change the output format. You could use this for logging errors instead.
public class GlobalExceptionMiddleware : OwinMiddleware
{
public GlobalExceptionMiddleware(OwinMiddleware next)
: base(next)
{
}
public override async Task Invoke(IOwinContext context)
{
try
{
await Next.Invoke(context);
}
catch (Exception ex)
{
context.Response.ContentType = "application/json";
context.Response.StatusCode = 500;
await context.Response.WriteAsync(JsonConvert.SerializeObject(ex));
}
}
}
Add the registration in OwinStartup.cs, just remember to place it before the MapSignalR method call:
public class OwinStartup
{
public void Configuration(IAppBuilder app)
{
app.Use<GlobalExceptionMiddleware>(); // must come before MapSignalR()
app.MapSignalR();
}
}
I am making our large set of web services available to AJAX calls. I have added the [System.Web.Script.Services.ScriptService] to each service. We have a registered HttpModule that initializes some objects we use regularly for logging and internationalization in the IHttpModule.Init override. It appears that the IHttpModule.Init is called when I make a SOAP request to any web method, but not when I make a JSON request to any web method. I've confirmed this by writing to a file when it's called.
Are HttpModules utilized when a .Net web service is called through the javascript proxy (AJAX)? If so, am I lacking some sort of configuration? Relevant code bits included below.
-colin-
Web.config:
<httpModules><add name="GlobalApplicationModule" type="Common.GlobalApplicationModule, Common"/></httpModules>
HTTPModules.cs:
class GlobalApplicationModule : IHttpModule
{
public void Dispose()
{
Internationalization.LanguageProvider.ReleaseAllResources();
}
public void Init(HttpApplication application)
{
// DEBUG: Confirm that this method is called
StreamWriter writer = new StreamWriter("c:\\deleteme-HTTP_module_test.txt");
writer.WriteLine("Init called.");
writer.Close();
// Initialize logger
Common.Logger.Initialize("LogAssemblyPath", "LogClassName");
Common.CentralConfiguration.CreateConfiguration(new Common.CentralizedStrategy());
// Initialize language provider
if (!Internationalization.LanguageProvider.Initialized)
{
try
{
string debug = System.Configuration.ConfigurationManager.AppSettings["debugInternationalization"];
string languageAssemblyLocation = System.Configuration.ConfigurationManager.AppSettings["LanguageAssemblyLocation"];
string languageAssemblyBaseName = System.Configuration.ConfigurationManager.AppSettings["LanguageAssemblyBaseName"];
languageAssemblyLocation = System.Web.HttpContext.Current.Server.MapPath(languageAssemblyLocation);
Internationalization.LanguageProvider.Init(languageAssemblyLocation, languageAssemblyBaseName, false);
if (debug != null && bool.Parse(debug))
{
Internationalization.LanguageProvider.PrefixText = "*";
}
}
catch (Exception x)
{
Common.Logger.Instance.LogError("Could not intialize assembly language provider. Error: " + x.Message);
}
}
}
}
That's a very odd debug logging method... Your problem is most likely due to your IIS configuration. It sounds like IIS is not handing off the request to ASP.NET at all. Check your mappings.