2013-01-08 30 views
1

在我們的應用程序中,我們使用MvcContrib生成鏈接,但Contrib似乎無法正常工作(或者我們做錯了什麼)的交叉區域鏈接除外。在服務中,我們有一個函數生成一個列表< ZakladkaModel>,其中包含通過自定義html助手生成tabstrib時使用的url和其他屬性。該函數將數據庫對象和UrlHelper的id作爲參數來幫助鏈接創建。url.Action與MvcContrib生成無效鏈接

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)) }); 

現在的問題是,在一些同事的計算機會生成鏈接的行爲正確和一些它看起來像它需要一個從我們的應用程序的raunom區域,並試圖建立一個無效的鏈接。我們可以使用一個簡單的url.Action(「action」,「controler」),它可以很好地工作,但我們更喜歡MvcContrib :)。有誰知道爲什麼會發生這種情況?或者可以分享一個替代品?

回答

1

看來,所使用的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