Removed MVC's custom request scope

We need to figure out a consistent way to throw errors when there isn't
a request scope already setup.
This commit is contained in:
David Fowler 2014-04-17 20:10:07 -07:00
parent b3d851dfe9
commit c4f01b8ec9
1 changed files with 33 additions and 72 deletions

View File

@ -1,10 +1,7 @@

using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNet.Abstractions;
using Microsoft.AspNet.DependencyInjection;
using Microsoft.AspNet.Mvc.Core;
using Microsoft.AspNet.Routing;
@ -26,85 +23,49 @@ namespace Microsoft.AspNet.Mvc
public async Task RouteAsync([NotNull] RouteContext context)
{
using (EnsureScopedServiceProvider(context.HttpContext))
var services = context.HttpContext.RequestServices;
Contract.Assert(services != null);
// TODO: Throw an error here that's descriptive enough so that
// users understand they should call the per request scoped middleware
// or set HttpContext.Services manually
var requestContext = new RequestContext(context.HttpContext, context.Values);
var actionSelector = services.GetService<IActionSelector>();
var actionDescriptor = await actionSelector.SelectAsync(requestContext);
if (actionDescriptor == null)
{
var services = context.HttpContext.RequestServices;
Contract.Assert(services != null);
var requestContext = new RequestContext(context.HttpContext, context.Values);
var actionSelector = services.GetService<IActionSelector>();
var actionDescriptor = await actionSelector.SelectAsync(requestContext);
if (actionDescriptor == null)
{
return;
}
var actionContext = new ActionContext(context.HttpContext, context.Router, context.Values, actionDescriptor);
var contextAccessor = services.GetService<IContextAccessor<ActionContext>>();
using (contextAccessor.SetContextSource(() => actionContext, PreventExchange))
{
var invokerFactory = services.GetService<IActionInvokerFactory>();
var invoker = invokerFactory.CreateInvoker(actionContext);
if (invoker == null)
{
var ex = new InvalidOperationException(
Resources.FormatActionInvokerFactory_CouldNotCreateInvoker(actionDescriptor));
// Add tracing/logging (what do we think of this pattern of tacking on extra data on the exception?)
ex.Data.Add("AD", actionDescriptor);
throw ex;
}
await invoker.InvokeActionAsync();
context.IsHandled = true;
}
}
}
private IDisposable EnsureScopedServiceProvider([NotNull] HttpContext httpContext)
{
if (httpContext.RequestServices != null)
{
// There's already a request-scope, we don't need to create one. It's safe to return null
// here, and that makes sure that we don't accidentally dispose the scope.
return null;
return;
}
var applicationServices = httpContext.ApplicationServices;
var actionContext = new ActionContext(context.HttpContext, context.Router, context.Values, actionDescriptor);
var scopeFactory = applicationServices.GetService<IServiceScopeFactory>();
var scope = scopeFactory.CreateScope();
var contextAccessor = services.GetService<IContextAccessor<ActionContext>>();
using (contextAccessor.SetContextSource(() => actionContext, PreventExchange))
{
var invokerFactory = services.GetService<IActionInvokerFactory>();
var invoker = invokerFactory.CreateInvoker(actionContext);
if (invoker == null)
{
var ex = new InvalidOperationException(
Resources.FormatActionInvokerFactory_CouldNotCreateInvoker(actionDescriptor));
var scopeHolder = new ScopeHolder(httpContext, scope);
httpContext.RequestServices = scope.ServiceProvider;
return scopeHolder;
// Add tracing/logging (what do we think of this pattern of tacking on extra data on the exception?)
ex.Data.Add("AD", actionDescriptor);
throw ex;
}
await invoker.InvokeActionAsync();
context.IsHandled = true;
}
}
private ActionContext PreventExchange(ActionContext contex)
{
throw new InvalidOperationException(Resources.ActionContextAccessor_SetValueNotSupported);
}
private class ScopeHolder : IDisposable
{
private readonly HttpContext _httpContext;
private readonly IServiceScope _scope;
public ScopeHolder([NotNull] HttpContext httpContext, [NotNull] IServiceScope scope)
{
_httpContext = httpContext;
_scope = scope;
}
public void Dispose()
{
_httpContext.RequestServices = null;
_scope.Dispose();
}
}
}
}