Asp.net mvc 基于特定值选择接口实例
我将从一点背景知识开始。我们有一个ASP.NETMVCWeb应用程序,它位于大致基于该概念的结构上。因此,我们有以下(简化的)垂直结构:Asp.net mvc 基于特定值选择接口实例,asp.net-mvc,design-patterns,architecture,domain-driven-design,Asp.net Mvc,Design Patterns,Architecture,Domain Driven Design,我将从一点背景知识开始。我们有一个ASP.NETMVCWeb应用程序,它位于大致基于该概念的结构上。因此,我们有以下(简化的)垂直结构: Net MVC控制器层 应用服务层 业务服务层 注意:上面的内容被简化了,因为它不涉及与此问题无关的视图、存储库、域对象等 对于水平结构,我们有一些主要区域由我们所称的“项目类型”定义(为了简单起见,这个问题将处理两个示例项目类型:“ItemTypeA”、“ItemTypeB”等) 我们有一个业务服务接口,每个项目类型有一个单独的实现: public in
- Net MVC控制器层
- 应用服务层
- 业务服务层
public interface ISampleBusinessService
{
string SampleMethod(string arg);
}
public class ItemTypeASampleBusinessService : ISampleBusinessService
{
public string SampleMethod(string arg)
{
return "Item Type A: " + arg;
}
}
public class ItemTypeBSampleBusinessService : ISampleBusinessService
{
public string SampleMethod(string arg)
{
return "Item Type B: " + arg;
}
}
位于上面的是使用业务服务的应用程序服务:
public interface ISampleAppService
{
string SampleMethod(string arg);
}
public class SampleAppService
{
private readonly ISampleBusinessService service;
public SampleAppService(ISampleBusinessService service)
{
this.service = service
}
public string SampleMethod(string arg)
{
return service.SampleMethod(arg);
}
}
坐在上面的是我们的控制器,它使用应用程序服务:
public class SampleController : Controller
{
private ISampelAppService service
public SampleController(ISampleAppService service)
{
this.service = service;
}
public PartialViewResult SampleAction(string arg)
{
return PartialView( service.SampleMethod(arg) );
}
}
请注意,控制器、应用程序服务接口和实现以及业务服务接口都是通用的,它们不关心使用哪种项类型。但是,业务服务实现是特定于项类型的。在调用控制器上的action方法时(通过视图中的RenderAction),我们知道要处理的是哪种项目类型,但我们不确定确定确定使用哪种业务服务实现的最佳方式。我们考虑了几个选项:
Zac这闻起来像是前面的大设计() 但是,很可能同时调用控制器和操作方法: 有关使用通用操作结果调用操作(产生相同效果)的一些信息 我非常喜欢这种方法,学习这些技术对任何想保持控制器超薄的人都有帮助
答复: 您实际上不需要调用泛型操作方法,只需要一种将泛型参数传递给控制器的方法。基本流程是将模型类型作为管线参数包含在内。您可以使用正确的RouteValueDictionary轻松调用通用渲染操作。以下是我的一个老项目中的一些示例代码: 开始我的通用控制器:
public GenericController()
{
TypeTranslator.Configure("Brainnom.Web.Model", "Brainnom.Web");
}
[UrlRoute(Path="admin/{modelType}/add", Order=9000)]
public virtual ActionResult Add()
{
return View( new MODEL() );
}
[HttpPost]
[UrlRoute(Path = "admin/{modelType}/add", Order = 9000)]
public virtual ActionResult Add( MODEL model, string modelType)
{
if (!ModelState.IsValid)
return View(model);
var postedModel = new MODEL();
UpdateModel(postedModel);
using (var session = new MongoSession())
{
session.Add(postedModel);
}
return RedirectToRoute("Browse", new { modelType });
}
还有我的GenericControllerFactory(有一天我确实需要重构)
使用系统;
使用System.Web.Mvc;
使用System.Web.Routing;
命名空间Brainnom.Web.Controllers
{
公共类GenericControllerFactory:DefaultControllerFactory
{
受保护的覆盖类型GetControllerType(System.Web.Routing.RequestContext RequestContext,string controllerName)
{
//泛型类型参数在这里并不重要
if(controllerName.EndsWith(“Co”)//假设我们这里没有任何其他通用控制器
返回类型(通用控制器);
返回base.GetControllerType(requestContext,controllerName);
}
受保护的覆盖IController GetControllerInstance(System.Web.Routing.RequestContext RequestContext,类型controllerType)
{
//我们要的是通用控制器吗?
if(requestContext.RouteData.Values.ContainsKey(“modelType”))
{
string typeName=requestContext.RouteData.Values[“modelType”].ToString();
//神奇时刻
返回GetGenericControllerInstance(typeName,requestContext);
}
如果(!typeof(IController).IsAssignableFrom(controllerType))
抛出新的ArgumentException(string.Format(“请求的类型不是控制器:{0}”)、controllerType.Name、“controllerType”);
返回base.GetControllerInstance(requestContext,controllerType);
}
///
///返回与请求的typeName关联的通用IController。
///因为我们只有一个通用控制器,所以现在类型是硬编码的
///
///
///
私有IController GetGenericControllerInstance(字符串类型名、RequestContext RequestContext)
{
var actionName=requestContext.RouteData.Values[“action”];
//尝试并解析自定义视图模型
Type actionModelType=Type.GetType(“Brainnom.Web.Models.”+typeName+actionName+“ViewModel,Brainnom.Web”,false,true)??
Type.GetType(“Brainnom.Web.Models.+typeName+”,Brainnom.Web”,false,true);
类型控制器Type=typeof(GenericController)。MakeGenericType(actionModelType);
var controllerBase=Activator.CreateInstance(controllerType,新对象[0]{})作为IController;
返回控制
using System;
using System.Web.Mvc;
using System.Web.Routing;
namespace Brainnom.Web.Controllers
{
public class GenericControllerFactory : DefaultControllerFactory
{
protected override Type GetControllerType(System.Web.Routing.RequestContext requestContext, string controllerName)
{
//the generic type parameter doesn't matter here
if (controllerName.EndsWith("Co"))//assuming we don't have any other generic controllers here
return typeof(GenericController<>);
return base.GetControllerType(requestContext, controllerName);
}
protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
{
//are we asking for the generic controller?
if (requestContext.RouteData.Values.ContainsKey("modelType"))
{
string typeName = requestContext.RouteData.Values["modelType"].ToString();
//magic time
return GetGenericControllerInstance(typeName, requestContext);
}
if (!typeof(IController).IsAssignableFrom(controllerType))
throw new ArgumentException(string.Format("Type requested is not a controller: {0}",controllerType.Name),"controllerType");
return base.GetControllerInstance(requestContext, controllerType);
}
/// <summary>
/// Returns the a generic IController tied to the typeName requested.
/// Since we only have a single generic controller the type is hardcoded for now
/// </summary>
/// <param name="typeName"></param>
/// <returns></returns>
private IController GetGenericControllerInstance(string typeName, RequestContext requestContext)
{
var actionName = requestContext.RouteData.Values["action"];
//try and resolve a custom view model
Type actionModelType = Type.GetType("Brainnom.Web.Models." + typeName + actionName + "ViewModel, Brainnom.Web", false, true) ??
Type.GetType("Brainnom.Web.Models." + typeName + ",Brainnom.Web", false, true);
Type controllerType = typeof(GenericController<>).MakeGenericType(actionModelType);
var controllerBase = Activator.CreateInstance(controllerType, new object[0] {}) as IController;
return controllerBase;
}
}
}