在我们的应用程序中,我们使用MvcContrib来生成链接,除了那些Contrib似乎不能正常工作的跨区域链接(或者我们做错了什么)。在服务中,我们有一个生成List
m_service.GenerowanieZakladkiDlaKontrolera_ARCH_Akt(idAktu, new UrlHelper(this.ControllerContext.RequestContext));
然后在GenerowanieZakladkiDlaKontrolera_ARCH_Akt中我们有这样的内容:
model.Add(new ZakladkaModel { Aktywnosc = true, NazwaZakladki = "Akt", Url = "" });
model.Add(new ZakladkaModel { Aktywnosc = true, NazwaZakladki = "Wzmianki", Url = url.Action<Usc.Presentation.Areas.FU_RAU.Controllers.ARCH.ARCH_WzmiankiController>(c => c.Index(idAktu)) });
if (tekstJednolity.StanTekstuJednolitego == "RB" || tekstJednolity.StanTekstuJednolitego == "SW")
{
model.Add(new ZakladkaModel { Aktywnosc = true, NazwaZakladki = "t.j. aktu", Url = url.Action<Usc.Presentation.Areas.FU_RAU.Controllers.ARCH.ARCH_TekstJednolityController>(c => c.Edytuj(tekstJednolity.Id)) });
}
else
{
model.Add(new ZakladkaModel { Aktywnosc = true, NazwaZakladki = "t.j. aktu", Url = url.Action<Usc.Presentation.Areas.FU_RAU.Controllers.ARCH.ARCH_TekstJednolityController>(c => c.Raport(tekstJednolity.Id)) });
}
model.Add(new ZakladkaModel { Aktywnosc = true, NazwaZakladki = "Przypisek 1", Url = url.Action<Usc.Presentation.Areas.FU_RAU.Controllers.ARCH.Przypisek1Controller>(c => c.Index(idAktu)) });
model.Add(new ZakladkaModel { Aktywnosc = true, NazwaZakladki = "Przypisek 2", Url = url.Action<Usc.Presentation.Areas.FU_RAU.Controllers.ARCH.Przypisek2Controller>(c => c.Index(idAktu)) });
model.Add(new ZakladkaModel { Aktywnosc = true, NazwaZakladki = "Przypisek 3", Url = url.Action<Usc.Presentation.Areas.FU_RAU.Controllers.ARCH.Przypisek3Controller>(c => c.Edytuj(idAktu)) });
model.Add(new ZakladkaModel { Aktywnosc = true, NazwaZakladki = "Przypisek 4", Url = url.Action<Usc.Presentation.Areas.FU_RAU.Controllers.ARCH.Przypisek4Controller>(c => c.Edytuj(idAktu)) });
现在的问题是,在一些同事的电脑上,它正确地生成链接到动作,在一些它看起来像它从我们的应用程序的一个随机区域,并试图使一个无效的链接。我们可以使用一个简单的url.Action("action","controller"),它可以很好地工作,但我们更喜欢MvcContrib:)。有人知道为什么会这样吗?或者可以分享另一种选择?
似乎LinkBuilder下使用不使用GetVirtualPatchForArea,因为我读到的是MVC错误。所以我决定创建自己的HtmlHelper,它使用这个方法:
public static string ActionArea<TController>(this HtmlHelper urlHelper, Expression<Action<TController>> expression) where TController : Controller
{
RouteValueDictionary routeValues = GetRouteValuesFromExpression(expression);
VirtualPathData vpd = new UrlHelper(urlHelper.ViewContext.RequestContext).RouteCollection.GetVirtualPathForArea(urlHelper.ViewContext.RequestContext, routeValues);
return (vpd == null) ? null : vpd.VirtualPath;
}
public static string ActionArea<TController>(this UrlHelper urlHelper, Expression<Action<TController>> expression) where TController : Controller
{
RouteValueDictionary routeValues = GetRouteValuesFromExpression(expression);
VirtualPathData vpd = urlHelper.RouteCollection.GetVirtualPathForArea(urlHelper.RequestContext, routeValues);
return (vpd == null) ? null : vpd.VirtualPath;
}
public static RouteValueDictionary GetRouteValuesFromExpression<TController>(Expression<Action<TController>> action) where TController : Controller
{
if (action == null)
{
throw new ArgumentNullException("action");
}
MethodCallExpression call = action.Body as MethodCallExpression;
if (call == null)
{
throw new ArgumentException("Akcja nie może być pusta.", "action");
}
string controllerName = typeof(TController).Name;
if (!controllerName.EndsWith("Controller", StringComparison.OrdinalIgnoreCase))
{
throw new ArgumentException("Docelowa klasa nie jest kontrolerem.(Nie kończy się na 'Controller')", "action");
}
controllerName = controllerName.Substring(0, controllerName.Length - "Controller".Length);
if (controllerName.Length == 0)
{
throw new ArgumentException("Nie można przejść do kontrolera.", "action");
}
// TODO: How do we know that this method is even web callable?
// For now, we just let the call itself throw an exception.
string actionName = GetTargetActionName(call.Method);
var rvd = new RouteValueDictionary();
rvd.Add("Controller", controllerName);
rvd.Add("Action", actionName);
var namespaceNazwa = typeof(TController).Namespace;
if(namespaceNazwa.Contains("Areas."))
{
int index = namespaceNazwa.IndexOf('.',namespaceNazwa.IndexOf("Areas."));
string nazwaArea = namespaceNazwa.Substring(namespaceNazwa.IndexOf("Areas.") + 6, index - namespaceNazwa.IndexOf("Areas.") + 1);
if (!String.IsNullOrEmpty(nazwaArea))
{
rvd.Add("Area", nazwaArea);
}
}
//var typ = typeof(TController).GetCustomAttributes(typeof(ActionLinkAreaAttribute), true /* inherit */).FirstOrDefault();
/*ActionLinkAreaAttribute areaAttr = typ as ActionLinkAreaAttribute;
if (areaAttr != null)
{
string areaName = areaAttr.Area;
rvd.Add("Area", areaName);
}*/
AddParameterValuesFromExpressionToDictionary(rvd, call);
return rvd;
}
private static string GetTargetActionName(MethodInfo methodInfo)
{
string methodName = methodInfo.Name;
// do we know this not to be an action?
if (methodInfo.IsDefined(typeof(NonActionAttribute), true /* inherit */))
{
throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture,
"Nie można wywoływać metod innych niż akcje.", methodName));
}
// has this been renamed?
ActionNameAttribute nameAttr = methodInfo.GetCustomAttributes(typeof(ActionNameAttribute), true /* inherit */).OfType<ActionNameAttribute>().FirstOrDefault();
if (nameAttr != null)
{
return nameAttr.Name;
}
// targeting an async action?
if (methodInfo.DeclaringType.IsSubclassOf(typeof(AsyncController)))
{
if (methodName.EndsWith("Async", StringComparison.OrdinalIgnoreCase))
{
return methodName.Substring(0, methodName.Length - "Async".Length);
}
if (methodName.EndsWith("Completed", StringComparison.OrdinalIgnoreCase))
{
throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture,
"Nie można wywoływać kompletnych metod.", methodName));
}
}
// fallback
return methodName;
}
static void AddParameterValuesFromExpressionToDictionary(RouteValueDictionary rvd, MethodCallExpression call)
{
ParameterInfo[] parameters = call.Method.GetParameters();
if (parameters.Length > 0)
{
for (int i = 0; i < parameters.Length; i++)
{
Expression arg = call.Arguments[i];
object value = null;
ConstantExpression ce = arg as ConstantExpression;
if (ce != null)
{
// If argument is a constant expression, just get the value
value = ce.Value;
}
else
{
value = CachedExpressionCompiler.Evaluate(arg);
}
rvd.Add(parameters[i].Name, value);
}
}
}
希望这对有类似问题的人有所帮助。上面的一些代码我从mvc2-rtm-sources修改到我的需要http://aspnet.codeplex.com/releases/view/41742