ASP.NET MVC局部视图中如何处理异常?

4
我有一个局部视图(ascx),用于显示个人RSS订阅的前x篇文章:
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IEnumerable<Models.Article>>" %>

    <% foreach (var item in Model) { %>

        <a href="<%: item.Url %>"><%: item.Title %></a><br />
        <%: String.Format("{0:g}", item.Date) %><br />
        <%: item.Body %>
        <br />

    <% } %>

此外,我有一个方法,它接受一个 RSS URL,并返回类型为 Article 的 IEnumerable。
public static class ArticleFeedHelper
{
    public static IEnumerable<Models.Article> GetArticles(string feedUrl)
    {
        // Uncaught exception can happen here (e.g. 404, malformed RSS, etc.)
    }
}

在我的一个视图中,我这样调用局部视图:
<div id="articleList" class="section">
    <div class="sectionTitle">My Recent Articles</div>
    <hr />
    <div class="sectionBody">
        <% Html.RenderPartial("ArticleList", ArticleFeedHelper.GetArticles(Model.RSSFeed)); %>
    </div>
</div>

问题在于我想将错误消息显示到主视图中。仅因无法检索到RSS源而不应该对用户造成如此大的干扰,以至于将其抛弃到完整的错误页面。
解决方法:
部分视图和ArticleFeedHelper保持不变。
使用 Dave's的建议,主视图已更改为:
<div id="articleList" class="section">
    <div class="sectionTitle">My Recent Articles</div>
    <hr />
    <div class="sectionBody">
        <% Html.RenderAction("ArticleList", "ArticleList", new { feedUrl = Model.RSSFeed }); %>
    </div>
</div>

添加了一个部分控制器:
public class ArticleListController : Controller
{
    public ActionResult Index()
    {
        return View();
    }

    [ChildActionOnly]
    public ActionResult ArticleList(string feedUrl)
    {
        try
        {
            IEnumerable<Models.Article> articles = Helpers.ArticleFeedHelper.GetArticles(feedUrl);
            return PartialView(articles);
        }
        catch (Exception ex)
        {
            // Handle the error and return an error partial view
        }
    }
}

并且添加了一条路由:

routes.MapRoute(
    "ArticleList", // Route name
    "{controller}/{action}/{feedUrl}", // URL with parameters
    new { controller = "ArticleList", action = "ArticleList", feedUrl = "" } // Parameter defaults
);
2个回答

3
更好的方法是使用RenderAction调用一个操作,该操作加载提要数据并可以捕获错误。
在ServicesController上的RssWidget action(实际上可以驻留在任何控制器中,没有关系,但我认为这是一个干净的解决方案):
此操作从提要中加载文章。请注意,代码仅为演示,您必须将RssService.GetArticles()替换为加载文章的实现。如果一切顺利,则返回一个PartialView(命名为RssWidget.ascx),显示文章列表。
public ServicesController : Controller
{
    public ActionResult RssWidget()
    {
        try
        { 
            var articles = RssService.GetArticles() // or whatever the articles'
                                                    // source is
            return PartialView(articles);
        }
        catch
        {
            return PartialView("Error");
        }
    }
}

RssWidget.ascx:这是用于呈现文章列表的(部分)视图。不要忘记将Article替换为您实际的文章类型:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IEnumerable<Article>>" %>

<% foreach(var article in Model) { %>
    <div class="article">
        <h3><%= Html.Encode(article.Title) %></h3>
        ...
    </div>
<% } %>

The View 是 RssWidget 显示的位置。您可以在任何视图中呈现此“小部件”。RenderAction("RssWidget", "Services") 告诉框架在 ServicesController 上执行 RssWidget 操作,并将结果插入实际视图中。

...
<div id="articleList" class="section">
    <div class="sectionTitle">My Recent Articles</div>
    <hr />
    <div class="sectionBody">
        <% Html.RenderAction("RssWidget", "Services"); %>
    </div>
</div>
...

我喜欢这个想法,但是模型如何传递给那个控制器呢? - Forgotten Semicolon
抱歉,我有点混淆了一些事情。我现在已经扩展了我的回答,希望现在更清楚了。 - davehauser

1

我个人认为不应该将文章的检索作为视图模板的一部分。我认为这不是数据集合和处理(控制器和模型)与数据呈现(视图)之间干净的分离。

你可以尝试在控制器或甚至模型中检索文章列表,具体取决于你处理服务样式依赖项的方式(我更倾向于控制器)。然后让你的视图仅能够处理将文章列表传递给局部视图,如果有一个的话,或者显示在收集数据期间发生的任何异常。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接