Initial hookin of ASP.Net WebApi V4 RC

--HG--
branch : 1.x
extra : transplant_source : %3A6%C7B%92%01%0Ep%D8%C7%17l%27%91%A4%7Cy%29BH
This commit is contained in:
Nicholas Mayne
2012-06-18 21:03:50 +01:00
parent 6bb550d574
commit cd7cf47aa3
23 changed files with 5517 additions and 0 deletions

View File

@@ -3,6 +3,8 @@ using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Web.Hosting;
using System.Web.Http;
using System.Web.Http.Dispatcher;
using System.Web.Mvc;
using Autofac;
using Autofac.Configuration;
@@ -28,6 +30,7 @@ using Orchard.Mvc.DataAnnotations;
using Orchard.Mvc.ViewEngines.Razor;
using Orchard.Mvc.ViewEngines.ThemeAwareness;
using Orchard.Services;
using Orchard.WebApi;
namespace Orchard.Environment {
public static class OrchardStarter {
@@ -141,6 +144,11 @@ namespace Orchard.Environment {
}
ControllerBuilder.Current.SetControllerFactory(new OrchardControllerFactory());
GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerSelector), new DefaultOrchardWebApiHttpControllerSelector(GlobalConfiguration.Configuration));
GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator), new DefaultOrchardWebApiHttpHttpControllerActivator(GlobalConfiguration.Configuration));
GlobalConfiguration.Configuration.DependencyResolver = new AutofacWebApiDependencyResolver(container);
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new ThemeAwareViewEngineShim());

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Web.Http.Controllers;
using System.Web.Mvc;
using Autofac.Core;
using Orchard.ContentManagement;
@@ -50,6 +51,7 @@ namespace Orchard.Environment.ShellBuilders {
var modules = BuildBlueprint(features, IsModule, BuildModule, excludedTypes);
var dependencies = BuildBlueprint(features, IsDependency, (t, f) => BuildDependency(t, f, descriptor), excludedTypes);
var controllers = BuildBlueprint(features, IsController, BuildController, excludedTypes);
var httpControllers = BuildBlueprint(features, IsHttpController, BuildController, excludedTypes);
var records = BuildBlueprint(features, IsRecord, (t, f) => BuildRecord(t, f, settings), excludedTypes);
var result = new ShellBlueprint {
@@ -134,6 +136,10 @@ namespace Orchard.Environment.ShellBuilders {
return typeof(IController).IsAssignableFrom(type);
}
private static bool IsHttpController(Type type) {
return typeof(IHttpController).IsAssignableFrom(type);
}
private static ControllerBlueprint BuildController(Type type, Feature feature) {
var areaName = feature.Descriptor.Extension.Id;

View File

@@ -17,6 +17,7 @@ namespace Orchard.Environment.ShellBuilders.Models {
public IEnumerable<DependencyBlueprint> Dependencies { get; set; }
public IEnumerable<ControllerBlueprint> Controllers { get; set; }
public IEnumerable<ControllerBlueprint> HttpControllers { get; set; }
public IEnumerable<RecordBlueprint> Records { get; set; }
}

View File

@@ -2,6 +2,7 @@
using System.IO;
using System.Linq;
using System.Web.Hosting;
using System.Web.Http.Controllers;
using System.Web.Mvc;
using Autofac;
using Autofac.Builder;
@@ -106,6 +107,17 @@ namespace Orchard.Environment.ShellBuilders {
});
}
foreach (var item in blueprint.HttpControllers) {
var serviceKeyName = (item.AreaName + "/" + item.ControllerName).ToLowerInvariant();
var serviceKeyType = item.Type;
RegisterType(builder, item)
.EnableDynamicProxy(dynamicProxyContext)
.Keyed<IHttpController>(serviceKeyName)
.Keyed<IHttpController>(serviceKeyType)
.WithMetadata("ControllerType", item.Type)
.InstancePerDependency();
}
// Register code-only registrations specific to a shell
_shellContainerRegistrations.Registrations(builder);

View File

@@ -49,6 +49,7 @@ namespace Orchard.Mvc.Routes {
// otherwise wrap handler and return it
routeData.RouteHandler = new RouteHandler(_workContextAccessor, routeData.RouteHandler);
routeData.Values["IWorkContextAccessor"] = _workContextAccessor; //NGM : Added for WebApi
routeData.DataTokens["IWorkContextAccessor"] = _workContextAccessor;
return routeData;
}

View File

@@ -105,6 +105,9 @@
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data" />
<Reference Include="System.Net.Http">
<HintPath>..\..\lib\aspnetwebapi\System.Net.Http.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.Serialization">
<RequiredTargetFramework>3.0</RequiredTargetFramework>
</Reference>
@@ -113,6 +116,12 @@
<Reference Include="System.Transactions" />
<Reference Include="System.Web" />
<Reference Include="System.Web.ApplicationServices" />
<Reference Include="System.Web.Http">
<HintPath>..\..\lib\aspnetwebapi\System.Web.Http.dll</HintPath>
</Reference>
<Reference Include="System.Web.Http.WebHost">
<HintPath>..\..\lib\aspnetwebapi\System.Web.Http.WebHost.dll</HintPath>
</Reference>
<Reference Include="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\aspnetmvc\System.Web.Mvc.dll</HintPath>
@@ -536,6 +545,11 @@
<Compile Include="Wcf\OrchardInstanceContext.cs" />
<Compile Include="Wcf\OrchardInstanceProvider.cs" />
<Compile Include="Wcf\OrchardServiceHostFactory.cs" />
<Compile Include="WebApi\AutofacWebApiDependencyResolver.cs" />
<Compile Include="WebApi\AutofacWebApiDependencyScope.cs" />
<Compile Include="WebApi\DefaultOrchardWebApiHttpControllerSelector.cs" />
<Compile Include="WebApi\DefaultOrchardWebApiHttpHttpControllerActivator.cs" />
<Compile Include="WebApi\Extensions\RouteExtension.cs" />
<Compile Include="WorkContextExtensions.cs" />
<Compile Include="Mvc\ViewEngines\Razor\RazorCompilationEventsShim.cs" />
<Compile Include="Mvc\ViewEngines\Razor\RazorViewEngineProvider.cs" />

View File

@@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using System.Web.Http.Dependencies;
using Autofac;
namespace Orchard.WebApi {
public class AutofacWebApiDependencyResolver : IDependencyResolver {
readonly ILifetimeScope _container;
readonly IDependencyScope _rootDependencyScope;
//internal static readonly string ApiRequestTag = "AutofacWebRequest";
public AutofacWebApiDependencyResolver(ILifetimeScope container) {
if (container == null) throw new ArgumentNullException("container");
_container = container;
_rootDependencyScope = new AutofacWebApiDependencyScope(container);
}
public ILifetimeScope Container {
get { return _container; }
}
public object GetService(Type serviceType) {
return _rootDependencyScope.GetService(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType) {
return _rootDependencyScope.GetServices(serviceType);
}
public IDependencyScope BeginScope() {
ILifetimeScope lifetimeScope = _container.BeginLifetimeScope();
return new AutofacWebApiDependencyScope(lifetimeScope);
}
public void Dispose() {
_rootDependencyScope.Dispose();
}
}
}

View File

@@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http.Dependencies;
using Autofac;
namespace Orchard.WebApi {
public class AutofacWebApiDependencyScope : IDependencyScope {
readonly ILifetimeScope _lifetimeScope;
public AutofacWebApiDependencyScope(ILifetimeScope lifetimeScope) {
_lifetimeScope = lifetimeScope;
}
public object GetService(Type serviceType) {
return _lifetimeScope.ResolveOptional(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType) {
if (!_lifetimeScope.IsRegistered(serviceType))
return Enumerable.Empty<object>();
var enumerableServiceType = typeof(IEnumerable<>).MakeGenericType(serviceType);
var instance = _lifetimeScope.Resolve(enumerableServiceType);
return (IEnumerable<object>)instance;
}
public void Dispose() {
if (_lifetimeScope != null)
_lifetimeScope.Dispose();
}
}
}

View File

@@ -0,0 +1,67 @@
using System;
using System.Net.Http;
using System.Web.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Dispatcher;
using Autofac;
using Autofac.Core;
using Autofac.Features.Metadata;
using Orchard.WebApi.Extensions;
namespace Orchard.WebApi {
public class DefaultOrchardWebApiHttpControllerSelector : DefaultHttpControllerSelector, IHttpControllerSelector {
private readonly HttpConfiguration _configuration;
public DefaultOrchardWebApiHttpControllerSelector(HttpConfiguration configuration) : base(configuration) {
_configuration = configuration;
}
/// <summary>
/// Tries to resolve an instance for the controller associated with a given service key for the work context scope.
/// </summary>
/// <typeparam name="T">The type of the controller.</typeparam>
/// <param name="workContext">The work context.</param>
/// <param name="serviceKey">The service key for the controller.</param>
/// <param name="instance">The controller instance.</param>
/// <returns>True if the controller was resolved; false otherwise.</returns>
protected bool TryResolve<T>(WorkContext workContext, object serviceKey, out T instance) {
if (workContext != null && serviceKey != null) {
var key = new KeyedService(serviceKey, typeof(T));
object value;
if (workContext.Resolve<ILifetimeScope>().TryResolveService(key, out value)) {
instance = (T)value;
return true;
}
}
instance = default(T);
return false;
}
public override HttpControllerDescriptor SelectController(HttpRequestMessage request) {
var routeData = request.GetRouteData();
// Determine the area name for the request, and fall back to stock orchard controllers
var areaName = routeData.GetAreaName();
var controllerName = base.GetControllerName(request);
// Service name pattern matches the identification strategy
var serviceKey = (areaName + "/" + controllerName).ToLowerInvariant();
HttpControllerContext controllerContext = new HttpControllerContext(_configuration, routeData, request);
// Now that the request container is known - try to resolve the controller information
Meta<Lazy<IHttpController>> info;
var workContext = controllerContext.GetWorkContext();
if (TryResolve(workContext, serviceKey, out info)) {
var type = (Type)info.Metadata["ControllerType"];
return
new HttpControllerDescriptor(_configuration, controllerName, type);
}
return null;
}
}
}

View File

@@ -0,0 +1,68 @@
using System;
using System.Net.Http;
using System.Web.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Dispatcher;
using Autofac;
using Autofac.Core;
using Autofac.Features.Metadata;
using Orchard.WebApi.Extensions;
namespace Orchard.WebApi {
public class DefaultOrchardWebApiHttpHttpControllerActivator : IHttpControllerActivator {
private readonly HttpConfiguration _configuration;
public DefaultOrchardWebApiHttpHttpControllerActivator(HttpConfiguration configuration) : base() {
_configuration = configuration;
}
/// <summary>
/// Tries to resolve an instance for the controller associated with a given service key for the work context scope.
/// </summary>
/// <typeparam name="T">The type of the controller.</typeparam>
/// <param name="workContext">The work context.</param>
/// <param name="serviceKey">The service key for the controller.</param>
/// <param name="instance">The controller instance.</param>
/// <returns>True if the controller was resolved; false otherwise.</returns>
protected bool TryResolve<T>(WorkContext workContext, object serviceKey, out T instance) {
if (workContext != null && serviceKey != null) {
var key = new KeyedService(serviceKey, typeof(T));
object value;
if (workContext.Resolve<ILifetimeScope>().TryResolveService(key, out value)) {
instance = (T)value;
return true;
}
}
instance = default(T);
return false;
}
public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType) {
var routeData = request.GetRouteData();
HttpControllerContext controllerContext = new HttpControllerContext(_configuration, routeData, request);
// Determine the area name for the request, and fall back to stock orchard controllers
var areaName = routeData.GetAreaName();
// Service name pattern matches the identification strategy
var serviceKey = (areaName + "/" + controllerDescriptor.ControllerName).ToLowerInvariant();
// Now that the request container is known - try to resolve the controller information
Meta<Lazy<IHttpController>> info;
var workContext = controllerContext.GetWorkContext();
if (TryResolve(workContext, serviceKey, out info)) {
controllerContext.ControllerDescriptor =
new HttpControllerDescriptor(_configuration, controllerDescriptor.ControllerName, controllerType);
var controller = info.Value.Value;
controllerContext.Controller = controller;
return controller;
}
return null;
}
}
}

View File

@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Http.Routing;
using System.Web.Mvc;
using System.Web.Routing;
namespace Orchard.WebApi.Extensions {
public static class RouteExtension {
public static string GetAreaName(this IHttpRoute route){
var routeWithArea = route as IRouteWithArea;
if (routeWithArea != null) {
return routeWithArea.Area;
}
var castRoute = route as Route;
if (castRoute != null && castRoute.DataTokens != null) {
return castRoute.DataTokens["area"] as string;
}
return null;
}
public static string GetAreaName(this IHttpRouteData routeData) {
object area;
if (routeData.Route.DataTokens.TryGetValue("area", out area)) {
return area as string;
}
return GetAreaName(routeData.Route);
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Web;
using System.Web.Http.Controllers;
using System.Web.Mvc;
using System.Web.Routing;
using Autofac;
@@ -29,6 +30,26 @@ namespace Orchard {
return workContextAccessor.GetContext(requestContext.HttpContext);
}
public static WorkContext GetWorkContext(this HttpControllerContext controllerContext) {
if (controllerContext == null)
return null;
var routeData = controllerContext.RouteData;
if (routeData == null || routeData.Values == null)
return null;
object workContextValue;
if (!routeData.Values.TryGetValue("IWorkContextAccessor", out workContextValue)) {
return null;
}
if (workContextValue == null || !(workContextValue is IWorkContextAccessor))
return null;
var workContextAccessor = (IWorkContextAccessor)workContextValue;
return workContextAccessor.GetContext();
}
private static object FindWorkContextInParent(RouteData routeData) {
object parentViewContextValue;
if (!routeData.DataTokens.TryGetValue("ParentActionViewContext", out parentViewContextValue)