posts - 202,  comments - 176,  trackbacks - 20
  2012年1月21日

在Asp.net MVC 3 web应用程序中,我们会用到ViewDataViewBag,对比一下:

ViewData ViewBag
它是Key/Value字典集合 它是dynamic类型对像
从Asp.net MVC 1 就有了 ASP.NET MVC3 才有
基于Asp.net 3.5 framework 基于Asp.net 4.0与.net framework
ViewData比ViewBag快 ViewBag比ViewData慢
在ViewPage中查询数据时需要转换合适的类型 在ViewPage中查询数据时不需要类型转换
有一些类型转换代码 可读性更好


在Controller中使用ViewData:

public ActionResult UsingViewData()
{
    
    ViewData["Title"] = " Using ViewData";
    ViewData["ProjectName"] = "My Test Project";
    ViewData["ProjectDescription"] = "This is Test Project to demo Viewdata and viewbag details";
    ViewData["StartDate"] = new DateTime(2011, 1, 1);
    ViewData["TotalPrice"] = 1000;
    ViewData["TotalDays"] = 100;
    Dictionary<string, string> stackholder = new Dictionary<string, string>();
    stackholder.Add("Client","Mr.  Client");
    stackholder.Add("Manager","Mr. Joy");
    stackholder.Add("Team Leader","Mr.Toy");
    stackholder.Add("Sr. developer", "Mr.dojoy");
    stackholder.Add("developer", "Mr. nodoy");
    ViewData["stackholder"] = stackholder;

    List<string> modules = new List<string>();
    modules.Add("Admin module");
    modules.Add("ShoppingCart module");
    modules.Add("CMS module");
    ViewData["modules"] = modules;
    return View();
}


对应UsingViewData View的cshtml:

<h1>@ViewData["Title"]</h1>
 <div>
   <div>
    <h2>Project Name : @ViewData["ProjectName"]</h2>
   </div>
   <div>
     ProjectDescription :   
     <p>"@ViewData["ProjectDescription"]".</p>
   </div>
   <div>
      Stack Holder :
      <br />

      <ul id="stakholder">
      @foreach ( var stakerholder in ViewData["stackholder"] as Dictionary<string, string> )
      {          
    <li>
        @stakerholder.Key &nbsp; : @stakerholder.Value
    </li>
      }
     </ul>
   </div>
   <div>
     Project Details:<br />
     <div>
       module List  :
       <ul id="modulelist">
      @foreach ( var module in ViewData["modules"] as List<string> )
      {          
    <li>
        @module
    </li>
      }
     </ul>
        
     </div>
     Project StartDate : @ViewData["StartDate"]  <br />
     Project TotalPrice: @ViewData["TotalPrice"] <br />
     Project TotaDays  : @ViewData["TotalDays"] 
   </div>
 </div>


然后是ViewBag:

public ActionResult UsingViewBag()
{

    ViewBag.Title = " Using ViewBag";
    ViewBag.ProjectName = "My Test Project";
    ViewBag.ProjectDescription = "This is Test Project to demo Viewdata and viewbag details";
    ViewBag.StartDate = new DateTime(2011, 1, 1);
    ViewBag.TotalPrice = 1000;
    ViewBag.TotalDays = 100;
    Dictionary<string, string> stackholder = new Dictionary<string, string>();
    stackholder.Add("Client", "Mr.  Client");
    stackholder.Add("Manager", "Mr. Joy");
    stackholder.Add("Team Leader", "Mr.Toy");
    stackholder.Add("Sr. developer", "Mr.dojoy");
    stackholder.Add("developer", "Mr. nodoy");
    ViewBag.stackholder = stackholder;

    List<string> modules = new List<string>();
    modules.Add("Admin module");
    modules.Add("ShoppingCart module");
    modules.Add("CMS module");
    ViewBag.modules = modules;
    return View();
}


对应View UsingViewBag 的cshtml的ViewBag:

<h1>@ViewBag.Title</h1>
 <div>
   <div>
    <h2>Project Name : @ViewBag.ProjectName</h2>
   </div>
   <div>
     ProjectDescription :   
     <p>"@ViewBag.ProjectDescription.</p>
   </div>
   <div>
      Stack Holder :
      <br />

      <ul id="stakholder">
      @foreach ( var stakerholder in ViewBag.stackholder )
      {          
    <li>
        @stakerholder.Key &nbsp; : @stakerholder.Value
    </li>
      }
     </ul>
   </div>
   <div>
     Project Details:<br />
     <div>
       module List  :
       <ul id="modulelist">
      @foreach ( var module in ViewBag.modules )
      {          
    <li>
        @module
    </li>
      }
     </ul>
        
     </div>
     Project StartDate : @ViewBag.StartDate.ToString("dd-MMM-yyyy") <br />
     Project TotalPrice: @ViewBag.TotalPrice  ₹  <br />
     Project TotaDays  : @ViewBag.TotalDays 
   </div>
 </div>


后面是在Controller中使用ViewBag:

public ActionResult UsingViewBagInControlAndViewDataInView()
{

    ViewBag.Title = " Using ViewBag In Control And ViewData In View";
    ViewBag.ProjectName = "My Test Project";
    ViewBag.ProjectDescription = "This is Test Project to demo Viewdata and viewbag details";
    ViewBag.StartDate = new DateTime(2011, 1, 1);
    ViewBag.TotalPrice = 1000;
    ViewBag.TotalDays = 100;
    Dictionary<string, string> stackholder = new Dictionary<string, string>();
    stackholder.Add("Client", "Mr.  Client");
    stackholder.Add("Manager", "Mr. Joy");
    stackholder.Add("Team Leader", "Mr.Toy");
    stackholder.Add("Sr. developer", "Mr.dojoy");
    stackholder.Add("developer", "Mr. nodoy");
    ViewBag.stackholder = stackholder;

    List<string> modules = new List<string>();
    modules.Add("Admin module");
    modules.Add("ShoppingCart module");
    modules.Add("CMS module");
    ViewBag.modules = modules;
    return View();
}


在UsingViewBagInControlAndViewDataInView.cshtml中使用ViewData来取值:

<h1>@ViewData["Title"]</h1>
 <div>
   <div>
    <h2>Project Name : @ViewData["ProjectName"]</h2>
   </div>
   <div>
     ProjectDescription :   
     <p>"@ViewData["ProjectDescription"]".</p>
   </div>
   <div>
      Stack Holder :
      <br />

      <ul id="stakholder">
      @foreach ( var stakerholder in ViewData["stackholder"] as Dictionary<string, string> )
      {          
    <li>
        @stakerholder.Key &nbsp; : @stakerholder.Value
    </li>
      }
     </ul>
   </div>
   <div>
     Project Details:<br />
     <div>
       module List  :
       <ul id="modulelist">
      @foreach ( var module in ViewData["modules"] as List<string> )
      {          
    <li>
        @module
    </li>
      }
     </ul>
        
     </div>
     Project StartDate : @ViewData["StartDate"]  <br />
     Project TotalPrice: @ViewData["TotalPrice"] <br />
     Project TotaDays  : @ViewData["TotalDays"] 
   </div>
 </div>


反过来是这样的:

public ActionResult UsingViewDataInControlAndViewBagInView()
{
    ViewData["Title"] = " Using ViewData In Control And ViewBag In View";
    ViewData["ProjectName"] = "My Test Project";
    ViewData["ProjectDescription"] = "This is Test Project to demo Viewdata and viewbag details";
    ViewData["StartDate"] = new DateTime(2011, 1, 1);
    ViewData["TotalPrice"] = 1000;
    ViewData["TotalDays"] = 100;
    Dictionary<string, string> stackholder = new Dictionary<string, string>();
    stackholder.Add("Client", "Mr.  Client");
    stackholder.Add("Manager", "Mr. Joy");
    stackholder.Add("Team Leader", "Mr.Toy");
    stackholder.Add("Sr. developer", "Mr.dojoy");
    stackholder.Add("developer", "Mr. nodoy");
    ViewData["stackholder"] = stackholder;

    List<string> modules = new List<string>();
    modules.Add("Admin module");
    modules.Add("ShoppingCart module");
    modules.Add("CMS module");
    ViewData["modules"] = modules;
    return View();
}


在UsingViewDataInControlAndViewBagInView.cshtml 的View中使用ViewBag来取值:

<h1>@ViewBag.Title</h1>
 <div>
   <div>
    <h2>Project Name : @ViewBag.ProjectName</h2>
   </div>
   <div>
     ProjectDescription :   
     <p>"@ViewBag.ProjectDescription.</p>
   </div>
   <div>
      Stack Holder :
      <br />

      <ul id="stakholder">
      @foreach ( var stakerholder in ViewBag.stackholder )
      {          
    <li>
        @stakerholder.Key &nbsp; : @stakerholder.Value
    </li>
      }
     </ul>
   </div>
   <div>
     Project Details:<br />
     <div>
       module List  :
       <ul id="modulelist">
      @foreach ( var module in ViewBag.modules )
      {          
    <li>
        @module
    </li>
      }
     </ul>
        
     </div>
     Project StartDate : @ViewBag.StartDate.ToString("dd-MMM-yyyy") <br />
     Project TotalPrice: @ViewBag.TotalPrice  ₹  <br />
     Project TotaDays  : @ViewBag.TotalDays 
   </div>
 </div>


这样对比看上去会比较清楚一些。在源代码中的ViewBag是这样的属性:

public dynamic ViewBag {
    get {
        if (_dynamicViewData == null) {
            _dynamicViewData = new DynamicViewDataDictionary(() => ViewData);
        }
        return _dynamicViewData;
    }
}

ViewData是:

public ViewDataDictionary ViewData {
    get {
        if (_viewData == null) {
            SetViewData(new ViewDataDictionary());
        }
        return _viewData;
    }
    set {
        SetViewData(value);
    }
}

具体细节在这儿不深入了,这里只是抛砖引玉。希望对您Asp.net MVC开发有帮助。

 


作者:Petter Liu
出处:http://www.cnblogs.com/wintersun/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
该文章也同时发布在我的独立博客中-Petter Liu Blog

posted @ 2012-01-21 15:48 PetterLiu 阅读(426) 评论(0) 编辑

       Asp.net MVC 3 应用程序中,单元测试对项目的质量意义重大。除了对Model,Controller进行单元测试,有时还需要对View也进行。对View进行测试目前并不容易做,大多数情况下可能做的是BlackBox测试。现在可以使用Razor Generator简化对Razor View单元测试。你可以从这里安装 VS2010的扩展。

      然后在VIEW上右键属性,对Custom Tool 使用Razor Generator,如下图,它就生成一个对应名称的Class, 文件与View在同一位置。

      image

然后我们看这个Class是这样的:

    [System.CodeDom.Compiler.GeneratedCodeAttribute("RazorGenerator", "1.3.0.0")]
    [System.Web.WebPages.PageVirtualPathAttribute("~/Views/Home/TestViewInOutTime.cshtml")]
    public class TestViewInOutTime : System.Web.Mvc.WebViewPage<dynamic>
    {
        public TestViewInOutTime()
        {
        }
        public override void Execute()
        {

            
            #line 1 "..\..\Views\Home\TestViewInOutTime.cshtml"
  
    Layout = null;


            
            #line default
            #line hidden
WriteLiteral("\r\n<!DOCTYPE html>\r\n\r\n<html>\r\n<head>\r\n    <title>TestViewInOutTime</title>\r\n</head" +
">\r\n<body>\r\n    <div>\r\n        <h1 id=\"titleOne\">This is your life</h1>\r\n    </di" +
"v>\r\n</body>\r\n</html>\r\n");


        }
    }

 

这个View的内容是:

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <title>TestViewInOutTime</title>
</head>
<body>
    <div>
        <h1 id="titleOne">This is your life</h1>
    </div>
</body>
</html>


好的,接下来在你的单元测试项目中使用NuGet安装RazorGenerator.Testing, 它有下面的依赖组件同是安装:

HtmlAgilityPack

Moq

ReflectionMagic


接着我们就可以写这样的单元测试代码。

[TestMethod]
public void TestGetGivenIdInnerHtmlFromViews()
{
    //arrange
    var views = new TestViewInOutTime();

    //act
    HtmlDocument doc = views.RenderAsHtml();
    HtmlNode node = doc.GetElementbyId("titleOne");

    //assert
    Assert.IsNotNull(node);
    Assert.AreEqual("This is your life", node.InnerHtml.Trim());
}


上面的代码您可能看到把当前View Render以后是一个HtmlDocument,这是HtmlAgilityPack中的类。HtmlAgilityPack是一个解析HTML的类库。

然后我们找到titleOne的结点比较的它的InnerHtml。那么对PartialView同样也可以:

Tel.cshtml内容是这样的:
021-77677878

代码是这样的:

[TestMethod]
public void TestPartialView()
{
    //arrange
    var views = new Tel();

    //act
    HtmlDocument doc = views.RenderAsHtml();

    //assert
    Assert.IsNotNull(doc);
    Assert.AreEqual("021-77677878", doc.DocumentNode.InnerText);
}


对Views的UnitTest本来就是棘手的事儿,因为View是在运行时编译的。但 Razor Generator 直接生成View类以方便我们测试它。那什么样产景下我们需要对View进行单元测试呢?有时我们没有必要比较整个输出的Html, 只需要比较是关键的某一段Html即可。

 

希望对您开发有帮助。


作者:Petter Liu
出处:http://www.cnblogs.com/wintersun/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
该文章也同时发布在我的独立博客中-Petter Liu Blog

posted @ 2012-01-21 10:41 PetterLiu 阅读(136) 评论(0) 编辑
  2012年1月7日

       有时程序使用HttpWebRequestHttpWebResponse实现HTTP的访问,但我们想测试它们不太容易实现。现在我们可以使用Moles框架来实现对它的单元测试。如果您还不了解Moles,可以先到官方网站看这个文档。下面我们来看片段代码:

[TestMethod]
[HostType("Moles")]
[Description("Testing with moles assemblies")]
public void Get_KnownUrl_ReturnsExpectedValue()
{
    var mockedWebResponse = new MHttpWebResponse();
    MHttpWebRequest.AllInstances.GetResponse = (x) =>
    {
        return mockedWebResponse;
    };

    var googleUri = new Uri("http://www.google.com");
    mockedWebResponse.StatusCodeGet = () => { return HttpStatusCode.OK; };
    mockedWebResponse.ResponseUriGet = () => { return googleUri; };
    mockedWebResponse.ContentTypeGet = () => { return "testHttpResponse"; };

    string mockedResponseStr = @"<html> \r\n" +
                         "  <head></head> \r\n" +
                         "  <body> \r\n" +
                         "     <h1>Hello World</h1> \r\n" +
                         "  </body> \r\n" +
                         "</html>";

    mockedWebResponse.ContentLengthGet = () => { return mockedResponseStr.Length; };

    using (var memoryStream = new MemoryStream())
    {
        using (var sw = new StreamWriter(memoryStream))
        {
            sw.Write(mockedResponseStr);
            sw.Flush();

            memoryStream.Seek(0, SeekOrigin.Begin);
            mockedWebResponse.GetResponseStream = () => memoryStream;


            //act
            var request = WebRequest.Create("http://www.google.com");
            var response = (HttpWebResponse)request.GetResponse();


            // Assert
            string htmlContent = null;
            using (var streamReader = new StreamReader(response.GetResponseStream()))
            {
                htmlContent = streamReader.ReadToEnd();
            }

            Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
            Assert.AreEqual(mockedResponseStr.Length, response.ContentLength);
            Assert.AreEqual(mockedResponseStr, htmlContent);
            Assert.AreEqual(googleUri, response.ResponseUri);

        }
    }
} 


上面的基于MsTest的代码引用Moles生成的System.Moles.dll,HttpWebRequestHttpWebResponse是在System.dll里的所以生成它。一开始对一些属性与方法的Mock操作,引用的是那些生成的MolesAssembiles,看字面意思可以了解代码的意图。接着模拟请求Google网站,返回我们遇先设置好返回的HtmlString,最后在验证中验证Stream,HttpStatusCode和Length是否一致。 当然您也可以测试其它属性成方法。注意最后请求的类是真实的类,可以演示我们把它们写在一起了。实际中可能是某个真实环境的API之类的方法。

希望对您开发有帮助。

 

您可以感兴趣的文章:

使用Moles对静态方法做UnitTest


作者:Petter Liu
出处:http://www.cnblogs.com/wintersun/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
该文章也同时发布在我的独立博客中-Petter Liu Blog

posted @ 2012-01-07 11:15 PetterLiu 阅读(72) 评论(0) 编辑
  2011年12月27日

     一般我们可以使用ref,out达到向外传递参数目的。 Action<T>是一个特殊的委托,除了常规应用。我们还可以用它来实现简单地向外传递参数。直接看下面的UnitTest代码:

   1: [TestMethod]
   2: public void PassOutParametersUsingDelegate()
   3: {
   4:     int i = 0;
   5:     string messgae = string.Empty;
   6:     int? addedNumber = 1;
   7:  
   8:     //It is pass parameter by Action<T1,T2>
   9:     Foo1((a, b) =>
  10:     {
  11:         i = a;
  12:         messgae = b;
  13:     });
  14:  
  15:     //It is pass parameter by Func<T1,T2,TResult>
  16:     Foo2((a, b) =>
  17:     {
  18:         i = a;
  19:         messgae = b;
  20:         return addedNumber;
  21:     });
  22:  
  23:     Foo2((a, b) =>
  24:     {
  25:         return a+100;
  26:     });
  27:  
  28:     Assert.AreEqual("i=15,message=fifteen", string.Format("i={0},message={1}", i, messgae));
  29:  
  30:  
  31: }
  32:  
  33: private void Foo1(Action<int, string> action)
  34: {
  35:     int number = 15;
  36:     string msg = "fifteen";
  37:  
  38:     action(number, msg);
  39: }
  40:  
  41: private void Foo2(Func<int, string, int?> func)
  42: {
  43:     int number = 15;
  44:     string msg = "fifteen";
  45:  
  46:     int? tempInt = func(number, msg);
  47: } 


上面的代码我们演示使用Action<T>, 有注意到我们把a,b两个值传递给方法外面的变量。同样的,我们用Func<TResult>可以实现。为什么会有这样的代码产生呢?源于这样的场景,有一个方法只有一个输入参数,返回void 。我们为了不改变原来这个方法参数签名,增加新的子方法,使用Action<T>向外传递参数。然后再用原方法Wrap新的子方法。
    关于Action<T>还有很多精彩的运用,Builder模式与Fluent接口
    希望对您开发有帮助。


作者:Petter Liu
出处:http://www.cnblogs.com/wintersun/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
该文章也同时发布在我的独立博客中-Petter Liu Blog

posted @ 2011-12-27 18:16 PetterLiu 阅读(65) 评论(0) 编辑
  2011年12月18日
摘要: 在Asp.net MVC 3 Web开发中,我们会大量使用各种ajax请求,针对ajax请求如何结何server端如何做异常处理呢?我们可以扩展ActionFilterAttribute,实现一个Ajax异常处理特性。假设您是使用JQuery脚本开发来实现Ajax,看代码: 1: #region AjaxExceptionAttribute 2: /...阅读全文
posted @ 2011-12-18 15:33 PetterLiu 阅读(212) 评论(0) 编辑
  2011年12月9日
摘要: Cross-Site Request Forgery (CSRF) 是我们Web站点中常见的安全隐患。 下面我们在Asp.net MVC3 来演示一下。 例如我们有一个HomeContoller中一个Submit Action,我们标记了Http Post[HttpPost]public ActionResult Submit(FormCollection fc){ if (!string.IsNullOrEmpty(fc["Title"])) { ViewBag.Message = "Submit success!"; return View(&quo阅读全文
posted @ 2011-12-09 20:23 PetterLiu 阅读(155) 评论(0) 编辑
  2011年12月2日
摘要: 首先,从CodePlex下载源码。 解压后编译一下,然后在我们要调试的Solution中开发那下面的项目: System.Web.Mvc System.Web.Helpers System.Web.WebPages System.Web.Razor System.Web.WebPages.Razor 同时也删除原来以上程序集原来的引用...阅读全文
posted @ 2011-12-02 18:50 PetterLiu 阅读(143) 评论(0) 编辑
  2011年11月27日
摘要: 延迟加载主要应用在以下场景: 数据层 – ADO.NET或Entity Framework等ORM反射 – 加载assemblies, types, MEF 缓存对象,领域实体 下面以领域实体为例, 在实体中我们经常检查某个属性下字段是否为空引用. 如果是空的话,计算或填充这个字段. 像这样: 1: /// <summary> 2: /// Order 3:...阅读全文
posted @ 2011-11-27 22:54 PetterLiu 阅读(164) 评论(0) 编辑
  2011年11月19日
摘要: 数据访问层在分层结构,比较常见. 有时可能是数据访问模块. 假设数据访问层后端是数据库,那我们如何测试他们的呢? 有时实际这种测试是集成测试了.有时数据库里还有一些逻辑,触发器,约束等. 个人十分不建议把业务逻辑放在数据库里实现. 最常见的数据库表的操作create, read, update和delete(简称CRUD), 例如我们需要测试某个Add方法,在这个测试方法完成后, 希望这条测试数...阅读全文
posted @ 2011-11-19 23:05 PetterLiu 阅读(185) 评论(0) 编辑
  2011年11月12日
摘要: Asp.net的NamePipe机制给我们提供了很多扩展性. 使用HttpModule我们可能实现的有: 强制站点范围的Cookie策略 集中化监控与日志 编写设置与删除HTTP头 控制response输出,如删除多余空白字符 Session管理 认证与受权 下面我们来看如何实现自定义异常处理: 1: public class ErrorModule:IHttpModule 2...阅读全文
posted @ 2011-11-12 16:55 PetterLiu 阅读(203) 评论(0) 编辑