mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-15 19:54:57 +08:00
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:
@@ -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());
|
||||
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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; }
|
||||
}
|
||||
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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" />
|
||||
|
41
src/Orchard/WebApi/AutofacWebApiDependencyResolver.cs
Normal file
41
src/Orchard/WebApi/AutofacWebApiDependencyResolver.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
33
src/Orchard/WebApi/AutofacWebApiDependencyScope.cs
Normal file
33
src/Orchard/WebApi/AutofacWebApiDependencyScope.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
34
src/Orchard/WebApi/Extensions/RouteExtension.cs
Normal file
34
src/Orchard/WebApi/Extensions/RouteExtension.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
@@ -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)
|
||||
|
Reference in New Issue
Block a user