前两天才做了一个Asp.Net MVC Preview2的实践,没想到这就升级到了Asp.Net Preview3了,Preview3确实比2好上不少,特别有两个地方值得注意,一是Route新增了MapRoute方法,可以更方便添加Url路由规则,二是修改了View的部分,使得Action统一返回ActionResult,更方便我们定制View.
前两天才做了一个Asp.Net MVC Preview2
的实践,
没想到这就升级到了Asp.Net Preview3
了,Preview3
确实比2
好上不少,
特别有两个地方值得注意,
一是Route
新增了MapRoute方法,可以更方便添加Url路由规则,二是修改了View的部分,使得Action统一返回ActionResult,更方便我们定制View.
今天我要实践的就是使用Priview3提供的新特性,通过自定义ActionResult实现Rss输出.
Rss在web系统中相当常见,主要用于快速浏览站点更新的文章等内容,是web2.0的主要特性之一,以前我们是如何来实现Rss输入的呢?在aspx中输出?自定义HttpHandle?自然是可以,但是到了MVC框架中,我们可以选中更好的方式,自定义ActionResult.
根据官方资料,每个Action都要返回一个ActionResult来执行View,而ActionResult是一个抽象类,我们现在必须的就是自定义一个RssAction.
首先根据需要建立一个ArticleResultDemo的Asp.Net Web Application.然后根据mvc约定建立相关文件夹和文件,为了实现rss输出,我添加以下文件,如图:

在Models中,ArticleEntity是Article对应实体,ArticleModel有一个测试方法供返回一组ArticleEntity,EntityExtensions是对Entity提供一组扩展方法,进行比如生成rss等功能,RssEntity是提供rss数据实体.在Controllers中,RssResult就是我们扩展的ActionResult,DemoController是扩展的Controller类,提供快捷的Rss输出方法,这是一个抽象类,ArticleController是当前Demo的主控制类.
关于这几个Entity类要说明下,RssEntity文件中包含RssEntity,RssImage,RssItem3个类,对整个rss数据进行了封装.EntityExtersions类提供一组扩展方法来实现实体-rss xml数据的转换,具体EntityExtersions的代码如下:
public static string ToXmlString(this RssItem item)

{
StringBuilder sb = new StringBuilder();
sb.AppendLine("<item>");
sb.Append(ToXmlItem<RssItem>(item));
sb.AppendLine("</item>");
return sb.ToString();
}

public static string ToXmlString(this RssImage image)

{
StringBuilder sb = new StringBuilder();
sb.AppendLine("<image>");
sb.Append(ToXmlItem<RssImage>(image));
sb.AppendLine("</image>");
return sb.ToString();
}

public static string ToXmlString(this RssEntity rss)

{
StringBuilder sb = new StringBuilder();
sb.AppendLine("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
sb.AppendLine("<rss version=\"2.0\">");
sb.AppendLine("<channel>");
sb.AppendLine(ToXmlItem<RssEntity>(rss));
sb.AppendLine("</channel>");
sb.AppendLine("</rss>");
return sb.ToString();
}

public static RssEntity ToDefaultRss(this IList<ArticleEntity> articleList)

{
RssEntity rss = new RssEntity()

{
Title = "ArticleResult Demo Rss.",
Copyright = "Copyright 2008 Leven",
Generator = "ArticleResult Demo",
Link = "http://blog.leven.com.cn/",
Description = "ArticleResult Demo Rss - a demo of asp.net mvc priview3.",
WebMaster = "leven",
Image = new RssImage()

{
Link = "http://blog.leven.com.cn/images/logo.jpg",
Title = "ArticleResult Demo",
Url = "http://blog.leven.com.cn/",
Description = "ArticleResult Demo Image."
}
};
foreach (ArticleEntity article in articleList)

{
rss.Items.Add(new RssItem()

{
Title = article.Title,
Author = article.PostUser,
Category = "Default Category",
Link = "http://blog.leven.com.cn/",
Guid = "http://blog.leven.com.cn/",
PubData = article.PostTime,
Description = article.Content
});
}
return rss;
}

private static string ToXmlItem<DType>(DType data)
where DType : class

{
StringBuilder sb = new StringBuilder();
Type type = data.GetType();
PropertyInfo[] pis = type.GetProperties();
foreach (PropertyInfo p in pis)

{
if (p.PropertyType == typeof(DateTime))

{
sb.AppendFormat("<{0}>{1:R}</{0}>\r\n", p.Name.ToLower(), p.GetValue(data, null));
}
else if (p.PropertyType == typeof(RssImage))

{
sb.AppendLine(((RssImage)p.GetValue(data, null)).ToXmlString());
}
else if (p.PropertyType == typeof(IList<RssItem>))

{
IList<RssItem> rssItems = p.GetValue(data, null) as IList<RssItem>;
foreach (RssItem item in rssItems)

{
sb.AppendLine(item.ToXmlString());
}
}
else

{
sb.AppendFormat("<{0}><![CDATA[{1}]]></{0}>\r\n", p.Name.ToLower(), p.GetValue(data, null));
}
}
return sb.ToString();
}

通过这些方法,我们可以方便生成rss数据.
再看RssResult类.该类继承自ActionResult类,实现了ExecuteResult方法.该方法为: ExecuteResult(ControllerContext context)我们可以在其中直接将rss数据输出.这便是ActionResult的魅力了,我们通过RssEntity+RssAction完全对实体-xml输出进行了封装,使得程序可以非常方便的实现rss输出.现给出RssResult的代码:

public Encoding ContentEncoding
{ get; set; }


public RssEntity Data
{ get; set; }

public RssResult()

{
}

public RssResult(Encoding encode)

{
ContentEncoding = encode;
}

public RssResult(RssEntity data, Encoding encode)

{
Data = data;
ContentEncoding = encode;
}

public override void ExecuteResult(ControllerContext context)

{
if (context == null)

{
throw new ArgumentNullException("context");
}
HttpResponseBase response = context.HttpContext.Response;
response.ContentType = "text/xml";
if (ContentEncoding != null)

{
response.ContentEncoding = ContentEncoding;
}
if (Data != null)

{
response.Write(Data.ToXmlString());
}
}

为了更方便使用这个RssResult,我们可以对Controller进行进一步的改写,这儿我参照了Json方法的方式实现了DemoController,代码如下:
public abstract class DemoController : Controller

{
[NonAction]
public ActionResult Rss(RssEntity rss, Encoding encode)

{
RssResult result = new RssResult(rss, encode);
return result;
}

[NonAction]
public ActionResult Rss(RssEntity rss)

{
RssResult result = new RssResult();
result.Data = rss;
return result;
}
}

由于这两个Rss方法并非Action,因此加上了[NonAction]的Attubite.
现在我们再使用就非常方便了,在ArticleController中,实现一个Rss方法
public ActionResult Rss()

{
RssEntity rss = ArticleModel.GetList().ToDefaultRss();
return Rss(rss);
}

一部直接输出了rss.最后修改web.config,添加route等完成之后,执行图如下:

说明一下,在priview3的官方说明中,为了使得默认首页可用,可以添加一个default.aspx文件,然后在页面中加入一行
<% Response.Redirect("article/rss")%>
我看到有朋友质疑说这个语法错误了,没有加分号,其实这是.net默认语言的问题,如果你不修改.net的配置,默认aspx的语言是vb.net的,因此这行是没有任何问题的.
最后给出该Demo的全部工程文件下载.
点击下载该工程文件
个人Blog同步更新:http://blog.leven.com.cn/Article_28.aspx
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步