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:
parent
b3d851dfe9
commit
c4f01b8ec9
|
|
@ -1,10 +1,7 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics.Contracts;
|
using System.Diagnostics.Contracts;
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Abstractions;
|
|
||||||
using Microsoft.AspNet.DependencyInjection;
|
using Microsoft.AspNet.DependencyInjection;
|
||||||
using Microsoft.AspNet.Mvc.Core;
|
using Microsoft.AspNet.Mvc.Core;
|
||||||
using Microsoft.AspNet.Routing;
|
using Microsoft.AspNet.Routing;
|
||||||
|
|
@ -26,85 +23,49 @@ namespace Microsoft.AspNet.Mvc
|
||||||
|
|
||||||
public async Task RouteAsync([NotNull] RouteContext context)
|
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;
|
return;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var applicationServices = httpContext.ApplicationServices;
|
var actionContext = new ActionContext(context.HttpContext, context.Router, context.Values, actionDescriptor);
|
||||||
|
|
||||||
var scopeFactory = applicationServices.GetService<IServiceScopeFactory>();
|
var contextAccessor = services.GetService<IContextAccessor<ActionContext>>();
|
||||||
var scope = scopeFactory.CreateScope();
|
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);
|
// Add tracing/logging (what do we think of this pattern of tacking on extra data on the exception?)
|
||||||
httpContext.RequestServices = scope.ServiceProvider;
|
ex.Data.Add("AD", actionDescriptor);
|
||||||
return scopeHolder;
|
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
await invoker.InvokeActionAsync();
|
||||||
|
|
||||||
|
context.IsHandled = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ActionContext PreventExchange(ActionContext contex)
|
private ActionContext PreventExchange(ActionContext contex)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException(Resources.ActionContextAccessor_SetValueNotSupported);
|
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue