0

管理領域内から、すべての領域の外部で共有されているエラービューにエラーリダイレクトを実行しようとしています。

ロビーコントローラーにエラーというメソッドを作成しました。

    public ViewResult Error()
    {
         return View("Views/Shared/Error");
    }

ビューはViews/Sharedディレクトリに存在し、エラーと呼ばれます。

管理領域のユーザーコントローラーから、次のことを実行しようとしています。

    return RedirectToAction("Error", "Lobby", new {area = ""});

ただし、routevaluesにarea = ""が含まれているにもかかわらず、アプリケーションは "/ Admin / Lobby/Error"にリダイレクトしようとしています。コードをステップスルーしようとすると、前の行とブラウザの404エラーの間に行が実行されません。

ここで何が欠けていますか?

追加するために編集:実際に私のルートに問題がある可能性があります。ログイン後にデフォルトの動作を変更して、エリア内にないコントローラーに直接送信しようとしましたが、自動的に管理エリアに送信されます。

私が達成しようとしていること:エリアがあるルートはそのエリアに行く必要があると解釈され、エリアがないルートはデフォルトを使用する必要があります。現在、私には1つの領域(管理者)しかありませんが、さらに多くの領域があります。

これが私のルートです:

routes.MapRoute("ErrorPage", "Error", new { controller="Error", action="Error"  },    new[] { "WebUI.Controllers" }); //Error Route

        routes.MapRoute(
            "", // Route name
            "Admin/{controller}/{action}/{id}", // URL with parameters
            new { area ="Admin", controller = "Client", action = "ManageClients", id = UrlParameter.Optional } // Parameter defaults
            , new[] { "WebUI.Areas.Admin.Controllers" } //prioritize admin
        );

        routes.MapRoute(
            "Default", // Route name
            "{controller}/{action}/{id}", // URL with parameters
            new { controller = "Lobby", action = "Index", id = UrlParameter.Optional } // Parameter defaults
            , new[] {"WebUI.Controllers"} //prioritize main
        );

IIRCがエリア名として「管理者」を「ハードコード」していないルートを使用しようとすると、ルーティングエンジンがエリアのないルートをエリアルートに詰め込もうとしたため、コントローラがエリアと間違えられました。コントローラのアクション。

ただし、現在実行しているのは、すべてのルートに「/Admin」を追加しているのではないかと思います。たとえば、アプリは起動時に最初にアカウント/ログインに移動します(エリア内ではありません)。ログイン動作を次の場所に変更したとき:

        return RedirectToAction("Summary", "Logging");

/ Logging/Summaryの代わりにURL/Admin / Logging/Summaryを形成しています。これを手動で変更しても

  return RedirectToAction("Summary", "Logging", new {area=""});

ルートから「デフォルト」の管理エリアを取得している必要があります。ただし、ルートからデフォルトエリアを削除すると、管理者リンクがすべて壊れます。

これは私のエリア登録がどのように見えるかです:

    public override void RegisterArea(AreaRegistrationContext context)
    {
        context.MapRoute(
            "Admin_default",
            "Admin/{controller}/{action}/{id}",
            new { action = "Index", id = UrlParameter.Optional },
         new [] { "WebUI.Areas.Admin.Controllers" }
        );
    }

したがって、質問を次のように言い換える必要があると思います。エリアの内側と外側の両方のルートとリンクが正しく機能するように、エリアとルートを構成するにはどうすればよいですか。

4

1 に答える 1

0

Phil HaackのAreaRouteHelper拡張機能をいくらか変更することで、問題を解決することになりました。

public static class AreaRouteHelper
{
    public static void MapAreas(this RouteCollection routes, string url, string rootNamespace, string[] areas)
    {
        Array.ForEach(areas, area =>
        {
            Route route = new Route("{area}/" + url, new MvcRouteHandler());
            route.Constraints = new RouteValueDictionary(new { area });
            string areaNamespace = rootNamespace + ".Areas." + area + ".Controllers";
            route.DataTokens = new RouteValueDictionary(new { namespaces = new string[] { areaNamespace } });
            route.Defaults = new RouteValueDictionary(new { action = "Index", controller = "Landing", id = "" });
            routes.Add(route);
        });
    }

    public static void MapRootArea(this RouteCollection routes, string url, string rootNamespace, object defaults)
    {
        Route route = new Route(url, new MvcRouteHandler());
        route.DataTokens = new RouteValueDictionary(new { namespaces = new string[] { rootNamespace + ".Controllers" } });
        route.Defaults = new RouteValueDictionary(new { area = "", action = "Index", controller = "Lobby", id = "" });
        routes.Add(route);
    }
}

(基本的に、デフォルトのRootAreaのデフォルトから「root」という単語を削除し、デフォルトをHomeではなく標準の「Lobby」と「Landing」に変更する必要がありました。デフォルトの「root」をそのままにしておくと、「ルート」が機能しなかったフォルダ構造に)

次に、RegisterRoutesから次の2つのルートを削除し、次のように置き換えました。

 routes.MapAreas("{controller}/{action}/{id}", "WebUI", new[] { "Admin", "Analysis" });

        routes.MapRootArea("{controller}/{action}/{id}",
            "WebUI",
            new { controller = "Lobby", action = "Index", id = "" });

この修正には、エリア対応のビューエンジンが必要です。Haackのプロジェクトの1つは1.0Webフォームビューエンジンです。私はすでにどこかで別の投稿から削り取ったエリア認識のかみそりビューエンジンを持っていて、これは機能しました。正直なところ、どの投稿で見つけたか覚えていないか、著者の功績を称えるために直接リンクします。しかし、これはどのように見えるかです(ここの誰かがそれを書いた人を知っているなら、私はそれをその人に喜んで帰します)。ここでのマッピングは私のプロジェクトと一致し、調整なしではおそらく他の人のマッピングとは一致しないことに注意してください。

 public class RazorAreaAwareViewEngine :RazorViewEngine
{
    private static readonly string[] EmptyLocations = { };

    public RazorAreaAwareViewEngine()
    {
        MasterLocationFormats = new string[]
                                    {
                                        "~/Views/{1}/{0}.master",
                                        "~/Views/Shared/{0}.master"
                                    };
        ViewLocationFormats = new string[]
                                  {
                                      "~/Areas/{2}/Views/{1}/{0}.cshtml",
                                      "~/Areas/{2}/Views/Shared/{0}.cshtml",
                                      "~/{2}/{0}.cshtml",
                                      "~/Views/{1}/{0}.cshtml",
                                      "~/Views/Shared/{0}.cshtml",
                                  };
        PartialViewLocationFormats = ViewLocationFormats;
    }
    public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName,string masterName, bool useCache)
    {
        if (controllerContext == null)
        {
            throw new ArgumentNullException("controllerContext");
        }
        if (string.IsNullOrEmpty(viewName))
        {
            throw new ArgumentNullException(viewName,
                "Value cannot be null or empty.");
        }
        string area = GetArea(controllerContext);

        return FindAreaView(controllerContext, area, viewName,
            masterName, useCache);
    }

    public override ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName,bool useCache)
    {
        if (controllerContext == null)
        {
            throw new ArgumentNullException("controllerContext");
        }
        if (string.IsNullOrEmpty(partialViewName))
        {
            throw new ArgumentNullException(partialViewName,
                "Value cannot be null or empty.");
        }
        string area = GetArea(controllerContext);

        return FindAreaPartialView(controllerContext, area,
            partialViewName, useCache);
    }

    protected string GetArea(ControllerContext controllerContext)
    {
        object area = null;
        if (controllerContext.RouteData.DataTokens.ContainsKey("area"))
        {
            area = controllerContext.RouteData.DataTokens["area"];
        }
        if (area == null)
        {
            controllerContext.RouteData.Values.TryGetValue("area", out area);
        }
        if(area !=null)
        {
            return area.ToString();
        }
        return null;
    }

    protected virtual ViewEngineResult FindAreaView(ControllerContext controllerContext, string areaName, string viewName,string masterName, bool useCache)
    {
        string controllerName =
            controllerContext.RouteData.GetRequiredString("controller");
        string[] searchedViewPaths;
        string viewPath = GetPath(controllerContext, ViewLocationFormats,
            "ViewLocationFormats", viewName, controllerName, areaName, "View",
            useCache, out searchedViewPaths);
        string[] searchedMasterPaths;
        string masterPath = GetPath(controllerContext, MasterLocationFormats,
            "MasterLocationFormats", masterName, controllerName, areaName,
            "Master", useCache, out searchedMasterPaths);
        if (!string.IsNullOrEmpty(viewPath) &&
            (!string.IsNullOrEmpty(masterPath) ||
              string.IsNullOrEmpty(masterName)))
        {
            return new ViewEngineResult(CreateView(controllerContext, viewPath,
                masterPath), this);
        }
        return new ViewEngineResult(
            searchedViewPaths.Union<string>(searchedMasterPaths));
    }

    protected virtual ViewEngineResult FindAreaPartialView(ControllerContext controllerContext, string areaName,string viewName, bool useCache)
    {
        string controllerName =
            controllerContext.RouteData.GetRequiredString("controller");
        string[] searchedViewPaths;
        string partialViewPath = GetPath(controllerContext,
            ViewLocationFormats, "PartialViewLocationFormats", viewName,
            controllerName, areaName, "Partial", useCache,
            out searchedViewPaths);
        if (!string.IsNullOrEmpty(partialViewPath))
        {
            return new ViewEngineResult(CreatePartialView(controllerContext,
                partialViewPath), this);
        }
        return new ViewEngineResult(searchedViewPaths);
    }

    protected string CreateCacheKey(string prefix, string name,
        string controller, string area)
    {
        return string.Format(CultureInfo.InvariantCulture,
            ":ViewCacheEntry:{0}:{1}:{2}:{3}:{4}:",
            base.GetType().AssemblyQualifiedName,
            prefix, name, controller, area);
    }

    protected string GetPath(ControllerContext controllerContext,string[] locations, string locationsPropertyName, string name,
        string controllerName, string areaName, string cacheKeyPrefix,bool useCache, out string[] searchedLocations)
    {
        searchedLocations = EmptyLocations;
        if (string.IsNullOrEmpty(name))
        {
            return string.Empty;
        }
        if ((locations == null) || (locations.Length == 0))
        {
            throw new InvalidOperationException(string.Format("The property " +
                "'{0}' cannot be null or empty.", locationsPropertyName));
        }
        bool isSpecificPath = IsSpecificPath(name);
        string key = CreateCacheKey(cacheKeyPrefix, name,
            isSpecificPath ? string.Empty : controllerName,
            isSpecificPath ? string.Empty : areaName);
        if (useCache)
        {
            string viewLocation = ViewLocationCache.GetViewLocation(
                controllerContext.HttpContext, key);
            if (viewLocation != null)
            {
                return viewLocation;
            }
        }
        if (!isSpecificPath)
        {
            return GetPathFromGeneralName(controllerContext, locations, name,
                controllerName, areaName, key, ref searchedLocations);
        }
        return GetPathFromSpecificName(controllerContext, name, key,
            ref searchedLocations);
    }

    protected string GetPathFromGeneralName(ControllerContext controllerContext,string[] locations, string name, string controllerName,
        string areaName, string cacheKey, ref string[] searchedLocations)
    {
        string virtualPath = string.Empty;
        searchedLocations = new string[locations.Length];
        for (int i = 0; i < locations.Length; i++)
        {
            if (string.IsNullOrEmpty(areaName) && locations[i].Contains("{2}"))
            {
                continue;
            }
            string testPath = string.Format(CultureInfo.InvariantCulture,
                locations[i], name, controllerName, areaName);
            if (FileExists(controllerContext, testPath))
            {
                searchedLocations = EmptyLocations;
                virtualPath = testPath;
                ViewLocationCache.InsertViewLocation(
                    controllerContext.HttpContext, cacheKey, virtualPath);
                return virtualPath;
            }
            searchedLocations[i] = testPath;
        }
        return virtualPath;
    }

    protected string GetPathFromSpecificName(ControllerContext controllerContext, string name, string cacheKey,ref string[] searchedLocations)
    {
        string virtualPath = name;
        if (!FileExists(controllerContext, name))
        {
            virtualPath = string.Empty;
            searchedLocations = new string[] { name };
        }
        ViewLocationCache.InsertViewLocation(controllerContext.HttpContext,
            cacheKey, virtualPath);
        return virtualPath;
    }

    protected static bool IsSpecificPath(string name)
    {
        char ch = name[0];
        if (ch != '~')
        {
            return (ch == '/');
        }
        return true;
    }


}

これらの変更を行った後、内側と外側の両方のアクションリンクが適切に生成され、内側と外側の両方のエリアをルーティングできました。

于 2012-06-20T22:44:17.037 に答える