我们已经开始执行我们的框架站点的Mvc3实现,目前使用我们现有的WebForms实现。
这项任务使我们能够将IoC和DI与Structuremap集成,以实现灵活性。
为了给你一些背景知识,我们有以下项目结构:
App.Core< - 核心类库
App.Mvc< - Mvc类库
App.Mvc.Web< - Mvc3 APP
App.WebForms< - Webforms类库
App.WebForms.Web< - Webforms app或site
我们在Mvc和WebForms实现上使用Mvc的路由,我们使用与Orchard项目相同的路由发布方法,使用IRouteProvider,其中可以创建N个IRouteProvider实现以添加路由出版商按其优先顺序进行注册和订购。
这很好,我们可以在MVC中使用UrlHelper或在WebForms中使用Page.GetRouteUrl注册和使用路由。
问题是我们现在要求App.Core也能够解析这些路由(不是所有路由,而是一些最常见的路由),这些路由可以根据正在实施的站点进行更改。
例如,产品详细信息默认路由可能是“/ {category} / {product_name} / {product_id}”,但我们希望能够覆盖此内容并且对于某个网站具有“/ {brand} / {product_name} / {product_id}“而不是。
这意味着在Core中我们不能简单地使用带有一组固定参数的RouteTable.Routes.GetVirtualPath,因为这些参数可能会因站点而异。
我们使用最常见路由的方法创建了一个IRouteResolver接口,该接口具有在每个类库(Mvc或Webforms)中向SM注册的默认实现,但也可以在每个站点上覆盖。
界面如下:
public interface IRouteResolver
{
string GetRouteUrl(object routeParameters);
string GetRouteUrl(RouteValueDictionary routeParameters);
string GetRouteUrl(string routeName, object routeParameters);
string GetRouteUrl(string routeName, RouteValueDictionary routeParameters);
string GetUrlFor(Product product);
string GetUrlFor(Category category);
string GetUrlFor(Brand brand);
}
界面的默认Mvc实现如下:
public class MvcRouteResolver : IRouteResolver
{
UrlHelper _urlHelper;
ICategoryModelBroker _categoryModelBroker;
IBrandModelBroker _brandModelBroker;
IProductModelBroker _productModelBroker;
public MvcRouteResolver(UrlHelper urlHelper)
{
_urlHelper = urlHelper;
_categoryModelBroker = ObjectFactory.GetInstance<ICategoryModelBroker>();
_brandModelBroker = ObjectFactory.GetInstance<IBrandModelBroker>();
_productModelBroker = ObjectFactory.GetInstance<IProductModelBroker>();
}
public string GetRouteUrl(object routeParameters)
{
return GetRouteUrl(new RouteValueDictionary(routeParameters));
}
public string GetRouteUrl(System.Web.Routing.RouteValueDictionary routeParameters)
{
return GetRouteUrl(null, new RouteValueDictionary(routeParameters));
}
public string GetRouteUrl(string routeName, object routeParameters)
{
return GetRouteUrl(routeName, new RouteValueDictionary(routeParameters));
}
public string GetRouteUrl(string routeName, System.Web.Routing.RouteValueDictionary routeParameters)
{
return _urlHelper.RouteUrl(routeName, routeParameters);
}
public string GetUrlFor(Product product)
{
string category = string.Empty;
if (product.Categories.Count > 0)
category = product.Categories[0].Breadcrumb.Replace("@@", "-");
else if (product.Brands.Any())
category = product.Brands.FirstOrDefault().Name;
else
category = "detail";
return GetRouteUrl(new { controller="Product", action="Detail", productId = product.Id, brandName = _productModelBroker.GetSlug(product), productName = _productModelBroker.GetSluggedName(product) });
}
public string GetUrlFor(Category category)
{
return GetRouteUrl(new { controller = "Product", action = "ListByCategory", id = category.Id, name = _categoryModelBroker.GetSlug(category) });
}
public string GetUrlFor(Brand brand)
{
return GetRouteUrl(new { controller = "Product", action = "ListByBrand", id = brand.Id, name = _brandModelBroker.GetSlug(brand) });
}
}
默认的WebForms实现如下:
public class WebRouteResolver : IRouteResolver
{
Control _control;
HttpContext _context;
public WebRouteResolver()
:this(HttpContext.Current)
{
}
public WebRouteResolver(HttpContext context)
{
_context = context;
}
public WebRouteResolver(Control control)
{
_control = control;
}
public WebRouteResolver(Page page)
{
_control = page as Control;
}
public string GetRouteUrl(object routeParameters)
{
return GetRouteUrl(new RouteValueDictionary(routeParameters));
}
public string GetRouteUrl(System.Web.Routing.RouteValueDictionary routeParameters)
{
return GetRouteUrl(null, new RouteValueDictionary(routeParameters));
}
public string GetRouteUrl(string routeName, object routeParameters)
{
return GetRouteUrl(routeName, new RouteValueDictionary(routeParameters));
}
public string GetRouteUrl(string routeName, System.Web.Routing.RouteValueDictionary routeParameters)
{
VirtualPathData virtualPath = null;
if(_control.IsNotNull())
virtualPath = RouteTable.Routes.GetVirtualPath(_control.Page.Request.RequestContext, routeName, routeParameters);
else
virtualPath = RouteTable.Routes.GetVirtualPath(_context.Request.RequestContext, routeName, routeParameters);
if (virtualPath != null)
{
return virtualPath.VirtualPath;
}
return null;
}
private string ResolveUrl(string originalUrl)
{
if(_control.IsNotNull())
return _control.ResolveUrl(originalUrl);
// *** Absolute path - just return
if (originalUrl.IndexOf("://") != -1)
return originalUrl;
// *** Fix up image path for ~ root app dir directory
if (originalUrl.StartsWith("~"))
{
string newUrl = "";
if (_context != null)
newUrl = _context.Request.ApplicationPath +
originalUrl.Substring(1).Replace("//", "/");
else
// *** Not context: assume current directory is the base directory
throw new ArgumentException("Invalid URL: Relative URL not allowed.");
// *** Just to be sure fix up any double slashes
return newUrl;
}
return originalUrl;
}
public string GetUrlFor(Product product)
{
string category = string.Empty;
if (product.Categories.Count > 0)
category = product.Categories[0].Breadcrumb.Replace("@@", "-");
else if (product.Brands.Any())
category = product.Brands.FirstOrDefault().Name;
else
category = "detail";
if (Config.RoutingEnabled)
{
return GetRouteUrl(new { @category = CommonHelper.ToFriendlyUrl(category), name = CommonHelper.ToFriendlyUrl(product.Name), id = product.Id });
}
return ResolveUrl(Config.GetStoreSetting("productDetailUrl")) + "?id={0}&name={1}&category={2}".Fill(product.Id, CommonHelper.ToFriendlyUrl(product.Name), CommonHelper.ToFriendlyUrl(category));
}
public string GetUrlFor(Category category)
{
string breadcrumb = category.Breadcrumb.Replace("@@", "-");
if (Config.RoutingEnabled)
return GetRouteUrl(new { @category = CommonHelper.ToFriendlyUrl(breadcrumb), category_id = category.Id});
return ResolveUrl(Config.GetStoreSetting("productListingUrl") + "?category_id={0}&category={1}".Fill(category.Id, CommonHelper.ToFriendlyUrl(category.Name)));
}
public string GetUrlFor(Brand brand)
{
if (Config.RoutingEnabled)
return GetRouteUrl(new { @brand = CommonHelper.ToFriendlyUrl(brand.Name), brand_id = brand.Id });
return ResolveUrl(Config.GetStoreSetting("productListingUrl") + "?brand_id={0}&brand={1}".Fill(brand.Id, CommonHelper.ToFriendlyUrl(brand.Name)));
}
}
现在的问题是,由于构造函数参数(Mvc上的UrlHelper和Webforms上的Page或Control),我们被迫使用具体类型而不是使用SM来获取IRouteResolver插件的实例。
例如,我有以下扩展名,以便在Page或Control
上使解析器可用public static IRouteResolver RouteResolver(this Control control)
{
return new WebRouteResolver(control);
}
public static IRouteResolver RouteResolver(this Page page)
{
return new WebRouteResolver(page);
}
这涵盖了Web或Mvc的默认行为,但不是我们希望在每个站点上专门覆盖解析器的情况。
问题是,在SM中添加这些构造函数参数作为插件是否安全?
您是否可以为此功能请求推荐其他方法/模式?
非常感谢任何想法/建议。
非常感谢, P上。
答案 0 :(得分:0)
我想我在Passing constructor arguments when using StructureMap
中找到了答案只要覆盖具有相同的构造函数,我认为:
public static IRouteResolver RouteResolver(this Control control)
{
return ObjectFactory.With("control").EqualTo(control).GetInstance<IRouteResolver>();
}
public static IRouteResolver RouteResolver(this Page page)
{
return ObjectFactory.With("page").EqualTo(page).GetInstance<IRouteResolver>();
}
可能有用,可以做一些测试
答案 1 :(得分:0)
我采取了另一种方法,上面没有在Core上运行。我现在只依靠RouteCollection和HttpContext来解析路由:
public abstract class BaseRouteResolver : IRouteResolver
{
protected HttpContext _context;
protected RouteCollection _routeCollection;
public BaseRouteResolver()
:this(RouteTable.Routes, HttpContext.Current)
{
}
public BaseRouteResolver(RouteCollection routeCollection, HttpContext context)
{
_routeCollection = routeCollection;
_context = context;
}
public string GetRouteUrl(object routeParameters)
{
return GetRouteUrl(new RouteValueDictionary(routeParameters));
}
public string GetRouteUrl(System.Web.Routing.RouteValueDictionary routeParameters)
{
return GetRouteUrl(null, new RouteValueDictionary(routeParameters));
}
public string GetRouteUrl(string routeName, object routeParameters)
{
return GetRouteUrl(routeName, new RouteValueDictionary(routeParameters));
}
public string GetRouteUrl(string routeName, System.Web.Routing.RouteValueDictionary routeParameters)
{
VirtualPathData virtualPath = _routeCollection.GetVirtualPath(_context.Request.RequestContext, routeName, routeParameters);
if (virtualPath != null)
return virtualPath.VirtualPath;
return null;
}
public abstract string GetUrlFor(Product product);
public abstract string GetUrlFor(Category category);
public abstract string GetUrlFor(Brand brand);
}