NullReferenceException when initializing NServiceBus within web application Application_Start method - asp.net

I am running the 2.0 RTM of NServiceBus and am getting a NullReferenceException when my MessageModule binds the CurrentSessionContext to my NHibernate sessionfactory.
From within my Application_Start, I call the following method:
public static void WithWeb(IUnityContainer container)
{
log4net.Config.XmlConfigurator.Configure();
var childContainer = container.CreateChildContainer();
childContainer.RegisterInstance<ISessionFactory>(NHibernateSession.SessionFactory);
var bus = NServiceBus.Configure.WithWeb()
.UnityBuilder(childContainer)
.Log4Net()
.XmlSerializer()
.MsmqTransport()
.IsTransactional(true)
.PurgeOnStartup(false)
.UnicastBus()
.ImpersonateSender(false)
.LoadMessageHandlers()
.CreateBus();
var activeBus = bus.Start();
container.RegisterInstance(typeof(IBus), activeBus);
}
When the bus is started, my message module starts with the following:
public void HandleBeginMessage()
{
try
{
CurrentSessionContext.Bind(_sessionFactory.OpenSession());
}
catch (Exception e)
{
_log.Error("Error occurred in HandleBeginMessage of NHibernateMessageModule", e);
throw;
}
}
In looking at my log, we are logging the following error when the bind method is called:
System.NullReferenceException: Object reference not set to an instance of an object.
at NHibernate.Context.WebSessionContext.GetMap()
at NHibernate.Context.MapBasedSessionContext.set_Session(ISession value)
at NHibernate.Context.CurrentSessionContext.Bind(ISession session)
Apparently, there is some issue in getting access to the HttpContext. Should this call to configure NServiceBus occur later in the lifecycle than Application_Start? Or is there another workaround that others have used to get handlers working within an Asp.NET Web application?
Thanks,
Steve

I wouldn't use WebSessionContext in this case, precisely because NServiceBus can operate independently of HttpContexts. If you want to use a single session context implementation for both web and NServiceBus message handling, I'd implement NHibernate.Context.ICurrentSessionContext with an hybrid storage, i.e. if HttpContext.Current != null, use the HttpContext as session storage. Otherwise use a thread local storage. This is similar to what Castle ActiveRecord does with its HybridWebThreadScopeInfo.

Related

.net transient database context being disposed prematurely

I am moving an asp.net mvc5 application using EF6 to asp.net core MVC 3.0 using EF Core.
In my mvc5 application I have some administrative operation that modify the database and take a long time, so I use a pattern when I create a new DBContext that is not the one that is associated with the request context and then run the task in the background using Task.Run. This has been working fine for years.
In converting to .net core it was unclear how to create a new DBContext in the way that I was doing it in my old codebase. It seems like I should be able to create a Transient DBContext in these cases and all should be fine.
So I created a subclass of MyDbContext called MyTransientDbContex and in my Configure class I added this service:
services.AddDbContext<MyTransientDbContex>(options =>
options.UseSqlServer(
context.Configuration.GetConnectionString("MyContextConnection")),
ServiceLifetime.Transient, ServiceLifetime.Transient);
In my controller I inject the context in the action that needs the transient service and spawn a thread to do something with it:
public ActionResult Update([FromServices] MyTransientContext context) {
Task.Run(() =>
{
try {
// Do some long running operation with context
}
Catch (Exception e) {
// Report Exception
}
finally {
context.Dispose();
}
}
return RedirectToAction("Status");
}
I would not expect my transient context to be disposed until the finally block. But I am getting this exception when attempting to access the context on the background thread:
Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling Dispose() on the context, or wrapping the context in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.
Object name: 'MyTransientContext'.'
And indeed the _disposed flag is set to true on the context object.
I put a breakpoint on the constructer for MyTransientContext and "Made an Object ID" of the this pointer so that I could track the object. This transient object is being created and is the same one that is inject into my controller action. It's also the same object that I'm trying to reference when the exception is thrown.
I tried setting a data breakpoint on the _disposed member in order to get a callstack on when disposed is being set to true, but the breakpoint won't bind.
I also tried overriding the Dispose method on MyTransientContext, and it isn't called until my explicit dispose in the finally block, which is after the exception is thrown and caught.
I feel like I'm missing something fundamental here. Isn't this what the transient services are for? What would dispose a Transient service?
One last detail - MyTransientContext is derived from MyContext, which is in turn derived from IdentityDbContext (Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityDbContex)
Edit: The reason that I went down the path of using a Transient was because of this ef core document page: https://learn.microsoft.com/en-us/ef/core/miscellaneous/configuring-dbcontext. It states that "...any code that explicitly executes multiple threads in parallel should ensure that DbContext instances aren't ever accessed concurrently. Using dependency injection, this can be achieved by either registering the context as scoped and creating scopes (using IServiceScopeFactory) for each thread, or by registering the DbContext as transient (using the overload of AddDbContext which takes a ServiceLifetime parameter)."
As xabikos pointed out, this seems to be overriden by the scoping of the asp.net DI system, where it looks like anything created by that system is scoped to the request context, including Transient objects. Can someone point out where that's documented so that I can better understand how to work with the limitations?
f you want manage the lifetime of service, you can instantiate it manually (or use a factory) :
public ActionResult Update()
{
Task.Run(() =>
{
using(var context = new MyTransientContext(...))
{
try
{
// Do some long running operation with context
}
catch (Exception e)
{
// Report Exception
}
}
}
return RedirectToAction("Status");
}
Or you can use IServiceProvider to get and manage a service :
public class MyController
{
private IServiceProvider _services;
public MyController(IServiceProvider services)
{
_services = services;
}
public ActionResult Update()
{
var context = (MyTransientContext)_services.GetService(typeof(MyTransientContext));
Task.Run(() =>
{
using (context)
{
try
{
// Do some long running operation with context
}
catch (Exception e)
{
// Report Exception
}
}
}
return RedirectToAction("Status");
}
}
You mixed the concepts of transient objects that are created by internal DI container asp.net core provides.
You configure the MyTransientContext to be transient in the internal DI system. This practically means that every time a scope is created then a new instance is returned. For asp.net application this scope matches an HTTP request. When the requests ends then all the objects are disposed if applicable.
Now in your code, that is a synchronous action method you spawn a Task with Task.Run. This is an async operation and you don't await for this. Practically during execution this will be started but not wait to finish, the redirect will happen and the request will end. At this point if you try to use the injected instance you will get the exception.
If you would like to solve this you need change to an async action and await on the Task.Run. And most likely you don't need to spawn a new Task. But you need to understand that this is not probably the best way as it will need for the long operation to finish before the redirect takes place.
An alternative to this would be to use a messaging mechanism, and send a message that triggers this operation. And you have another component, like worker service that listens for those messages and process them.

SignalR, Owin and exception handling

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();
}
}

Reporting errors from the application services layer

I'm implementing web application based on Spring MVC and organized around DDD concepts. Currently I try to implement ticket reservation functionality. The customer can see number of tickets available for the particular event. Then, he can enter number of tickets to be reserved and submit form. Request is received by controller which calls application service responsible for registration. Application service logic is as follows:
Validate incoming parameters:
1A. Check if event with the given ID exists
1B. Check if number of tickets available allows for reservation
If validation passed, proceed with registration; otherwise, report an error.
I have some doubts about the proper way for reporting validation errors - especially for point 1B. Situation when number of tickets does not allow for reservation is not something very unusual. Customer can see number of tickets that is not fully synchronized with current number of tickets in database (eventual consistency) - some other person could reserve some tickets in the meantime.
Initially I was thinking about reporting this problems by throwing some specific exceptions. However, I can think of couple of other problematic situations and having one exception for each on of them doesn't sound very well.
The other option I was considering was throwing one type of exception containing error code. However, I don't know how to handle this situation in Spring MVC properly.
What are the best practices for such problems? How do you deal with them in your MVC applications? Any advices greatly appreciated.
I think these are business constraint brokens that cannot be recovered.
My current solution is Exception hierachy.
public abstract class UncheckedApplicationException extends RuntimeException {
//omitted factory methods and constructors
public abstract String getStatusCode();
public abstract String getI18nCode();//ignore this if you don't need i18n
public abstract String[] getI18nArgs();//ignore this if you don't need i18n
}
Any custom exception extends this one. I think this could avoid code like this:
try {
//invoke your application service
} catch (InsufficientInventoryException e) {
statusCode = INSUFFICIENT_INVENTORY;
} catch (ExpriedPriceException e) {
statusCode = EXPIRED_PRICE;
} catch (NoSuchProductException e) {
statusCode = NO_SUCH_PRODUCT;
} catch (Exception e) {
statusCode = UNKNOWN;
}
Controller code snippet:
try {
//invoke your application service here
statusCode = SUCCESS;
message = messageSource.getSuccess(locale));
} catch (UncheckedApplicationException e) {
statusCode = e.getStatusCode();
message = messageSource.getMessage(e, locale));
} catch (Exception e) {
statusCode = UNKNOWN;
message = messageSource.getUnknownError(e, locale));
}
//add statusCode & message to modelAttribute
You can use #ExceptionHandler to reduce boilerplate try-catch code if your Controller is well organized(but pretty difficult).
The other reason to use Excepton is that application service is often used to delimit transaction boundary. An exception has to be thrown if you want to rollback.

Application_EndRequest triggered before request end?

I have some simple classes that need to be disposed a the end of the request.
For that end I call the Dispose method on those objects from the Application_EndRequest event in Global.asax.
This "works fine on my machine" but causes some problems on my production server where I get Cannot access a disposed object. This happens in some MVC helpers.
It seemed to me like Application_EndRequest is triggered at the end of the request. Is this not the case? Is there another event I should be using to dispose my objects?
Application pool issues - likely
I suspect that your disposable object isn't bound to request but rather app wide (it may be instantiated per request but it may be using some shared resources). As long as you're testing your application in development environment it seems to behave as expected but as soon as you put it in production you get issues. This indicates you may have problems with application pool.
IIS web application pool capabilities actually instantiate several HttpApplication instances for your application and they may all share common disposable resources. If that's the case with your disposable object and you're sharing it it may be that it isn't thread safe. The same would be true when you wouldn't wrap your shared resource usage inside thread safe operations.
That's why it may happen that while one request is in progress another one begins and the first one disposed the object while the second process still uses it.
More information is always helpful
If you'd explain the nature of your disposable object/resource and how you're using it in your application we could help you much better. But in the meantime, you could read my blog post that talks about application pools and handling them. It's not about disposable objects per se, but you may still find all the information very useful and helpful.
If you need some object disposable per-request to use inside your controllers, I would recommend you using controller's lifecycle handlers instead of using Application_BeginRequest and Application_EndRequest. See the following example.
The Controller:
public class BaseController : Controller
{
protected override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
this.HttpContext.Items["MyDisposableObject"] = new MyDisposableObject();
}
protected override void OnResultExecuted(ResultExecutedContext filterContext)
{
base.OnResultExecuted(filterContext);
if (this.HttpContext.Items.Contains("MyDisposableObject"))
{
var myDisposableObject =
this.HttpContext.Items["MyDisposableObject"] as IDisposable;
if (myDisposableObject != null)
{
myDisposableObject.Dispose();
}
}
}
}
The IDisposable object:
public sealed class MyDisposableObject : IDisposable
{
private bool disposed;
public void Dispose()
{
if (!this.disposed)
{
// Dispose all managed
// and unmanaged resources.
// Note disposing has been done.
this.disposed = true;
}
}
}
If the objects are scoped to controller level you can override the Dispose method of Controller to dispose those objects.
protected override void Dispose(bool disposing)
{
if(disposing)
{
// dispose the objects here
}
base.Dispose(disposing);
}
If you are using some DI framework (like Ninject) in your application you can delegate that job to them.
Instead of disposing the objects at the end of the request you can also try wrapping them in an using statement wherever you access by this way you make sure the object is disposed.

Globally handling exceptions in static aspx [WebMethods] in ASP.NET

The default behavior of a [WebMethod] attributed static method on an aspx page is to return the error to the caller. We are accessing these methods using json, and the only way we have found of capturing exceptions is either a try/catch in every webmethod on the site or using a javascript callback with the error (which has the unacceptable downside of exposing the error to the client).
Is there any way to globally handle these exceptions using the HealthMonitoring setup in ASP.NET?
I don't know about health monitoring, but I normally have a generic wrapper that executes the endpoint code inside. This records the real exception but always throws a generic exception across the boundry.
public static T wrapAjaxRequestsToCatchException<T>(Func<T> wrappedDelegate) where T : JsonBase, new()
{
try
{
return wrappedDelegate();
}
catch (Exception ex)
{
var errResponse = new T()
{
Success = false,
Message = getErrorMessage(ex)
};
// Log the exception
ErrorLog.LogAjaxEvent(string.Format("AJAX EXCEPTION : {0}", ex.ToString()), System.Diagnostics.EventLogEntryType.Error);
return errResponse;
}
}

Resources