[转载]Asp.net MVC 3 Framework: SportsStore源码

mikel阅读(1571)

[转载]Asp.net MVC 3 Framework: SportsStore源码 – 叶华斌 – 博客园.

   由于项目的要求,开始抽时间看些ASP.NET mvc方面的资料,主要参考的书籍是Pro ASP.NET MVC 3 Frameworkpdf下载) 。跟着里面的讲解将SportsStore做了一遍以加深理解。有需要代码的童鞋可以在下面下载以供学习参考。

我使用的开发工具是visual studio 2012+SQL server 2008

 

项目组织结构:

 

SportsStore 前台首页:

SportsStore 分类显示:

SportsStore 购物车功能:

SportsStore 提交订单:

 

 

后台登录页面:

 

SportsStore 产品管理:

 

点击下载》》

[转载]jQuery EasyUI 1.3.0 Demo合集、离线API、动态换肤

mikel阅读(1133)

[转载][原]jQuery EasyUI 1.3.0 Demo合集、离线API、动态换肤 – purediy – 博客园.

JQuery EasyUI 1.3 Demo合集、离线API、动态换肤。

JQuery EasyUI 1.2.6源码 Demo合集 离线API 的时候就发现作者要放出来1.3了,前段时间发现已经更新了,没来得及整理,现给出JQuery EasyUI 1.3 Demo合集、离线API,以及把easyui的各种皮肤整合在一起,包括官网上的扩张皮肤,可以动态换肤了。这次没有像1.2.6翻译的源码,暂时也没用到,使用的时候再说吧。

打包地址猛击下载,http://files.cnblogs.com/purediy/jquery-easyui-1.3.0.zip

Demo预览图片

demo

API预览图片

API

[转载]如何写出兼容大部分浏览器的CSS 代码

mikel阅读(1100)

转载如何写出兼容大部分浏览器的CSS 代码 – LoveJenny – 博客园.

前阵子一直在从事b/s 项目的开发,在css 方面有一些心得体会,特写来与大家分享,欢迎大家评论,不过请勿人身攻击啊,因为在前几年我也写过一篇文章:[原]兼容浏览器的布局CSS心得体会

楼下有很多人的评论:

image

image

image

就让我继续毁人吧。

 

1:使用Firefox 当主开发浏览器

为什么我推荐使用firefox 做为主开发浏览器,

首先目前市场上浏览器很多,ie6 + ,firefox ,opera,chrome,qq 浏览器,360浏览器,搜狗浏览器…

为什么我把qq 浏览器,360浏览器,搜狗浏览器 这些也算进去,是因为这些浏览器虽然使用ie的内核,但是在某些地方显示的效果不一样。

有很多人在开发的时候选择ie 做为浏览器,当然我认为如果使用ie 做为主开发浏览器的话,那应该是使用

ie8+ ,毕竟在ie8+ 的时候才出现了比较强大的工具,另外如果使用ie的话,那么你经常问自己的问题是“ie 下显示正常,为什么firefox 下显示不正常呢?”,这点后面会有解释。

 

回归正题:我推荐使用firefox 做为主开发浏览器的原因:

a:firefox 下面有开发神器firebug.

firebug 究竟有多厉害,相信使用过的人都知道的,另外firebug 还有yslow,等一系列测速插件,并且firebug启动速度也比较快。

b:firefox 有很多开发插件,虽然firebug已经很出色了,但是这些插件在某些地方还是很有用的。

c:firefox 是遵守css 标准的浏览器,众所周知ie 在这方面做的比较烂。

以前我曾经看过一篇文章,大致讲的是

“ie 下显示正常,为什么firefox 下显示不正常呢?”,

其实我感觉应该这样理解

“为什么firefox 下显示不正常,但是在ie下显示正常呢?”

因为当你这样问自己后,你自己就会去查找,究竟是哪些元素ie没有遵守css 标准呢。

d:firebug 虽然有控制台,但是有时候JavaScript 代码console.write(“something”);,并不会正常的显示到控制台上面去,

当你碰到console 失败的时候,请尝试下下面的步骤

1:启用firebug

image

2:禁用所有面板和清空激活列表。

image

3:重新启用firebug。

image

2:使用reset.css

使用reset.css 可以省掉很多事情,比如ul ,li 他们在很多浏览器下面的margin ,padding 都不一样,

通过使用reset.css 可以将大部分不一致的地方给屏蔽掉,没有理由不使用reset.css啊。

下面是我随便挑选的一个reset.css.

yui reset.css

3:学习一些基本的CSS 知识

如果想写好css 的话,那么一些基本的css知识是应该知道的,比如float,margin,padding,position..属性,还有盒子模型,文档流模型,在这里没什么技巧,我只能推荐一些书籍了。

精通CSS:高级Web标准解决方案(第2版)

一些基本的书籍随便看看,上面的这本书籍才是经典中的经典,个人认为学css不看这本书,看遍千本也枉然。

 

4:常见的bug

常见的一些bug你应该都知道的,事实上在我写css的这段时间,我发现大部分bug 都基本上是这些bug,大部分显示不正确的也是这些bug.

a:clearfix

在很多时候一刀切是非常管用的,尤其是对于那些非常喜欢用float的同学。

.clearfix:before, .clearfix:after { content:""; display:table; } .clearfix:after{ clear:both; overflow:hidden; } .clearfix{ *zoom:1; }

b:double margin (双倍边距)

有时候你会发现两个元素的margin 在不同的浏览器上显示不一样,如果你查看css 的时候发现你设置了float的话,那么很可能你碰到了double margin.  解决这个办法的原因很简单,比如设置margin 为0 (即不使用margin,我最早就是这种想法),

最根本的是设置float 元素的display = “inline”.

由于float 元素本来display 就是inline .所以每当你要使用float 的时候,请记住将display 设为inline.

 

c:关于width ,height,line-height,border

border 是一个很好用的东西,在很多时候,仅仅给元素加个border就解决实际问题了,因为加了border的元素在ie 下面就有了hasLayout 属性。

line-height 也是一个非常让人头痛的属性,有时候你会发现无论你怎么设置height,height 好像不起作用似的,height不起作用有可能是display :line ,也有可能float,同样也有可能是line-height。

有人说过只要是float 的对象就应该设置width,height,关于这点我认为在某些情况下设置width 是必要的,但是设置height 就不一定了。

d:bug 其实没有那么多

有很多些css 的同学,当碰到一两个比较棘手的问题的时候,就说这个是ie的bug,可是大部分情况下,是自己的写法没有符合标准,或者是没有正确的理解css,所以他 们经常做的就是,试试加个width,加个height。试试加个border,试试修改下margin,padding。 当然很多时候运气比较好,一下就加对了,但运气不好的时候就比较郁闷了。解决了bug 是运气,没解决bug就是ie的bug,可是事实上ie 的bug 大部分都曾经出现过,所以在对待bug 的时候,还是要心平气和的分析问题,解决问题。

 

5:应该记住的一些浏览器css写法

如果你使用firefox 做为主开发浏览器的话,我相信你的页面在opera,chrome 下应该也不会太乱,但是ie 我就不敢保证了,这个时候就应该调整ie 兼容性了。

有很多种方式,比如使用条件注释针对各个ie 浏览器引入不同的css。

<!--[if IE 5]>仅IE5.5可见<![endif]--> <!--[if gt IE 5.5]>仅IE 5.5以上可见<![endif]--> <!--[if lt IE 5.5]>仅IE 5.5以下可见<![endif]--> <!--[if gte IE 5.5]>IE 5.5及以上可见<![endif]--> <!--[if lte IE 5.5]>IE 5.5及以下可见<![endif]--> <!--[if !IE 5.5]>非IE 5.5的IE可见<![endif]>

 

我个人比较喜欢的一种方式还是使用css hacker.

我是从ie8,ie7,ie6,逐渐的调的,因为越到后面需要调的东西越多,而通过这种方式来调的话,我的css 代码改动是比较小的,即所谓的小步前进吧。

首先找出是哪个元素引起布局混乱,然后看看是不是属于哪些常见的bug,接着给这个元素设定一个

border.

通过慢慢的查找,相信除了ie6 ,布局应该都是ok的。但是ie6应该怎么做呢?

image

我比较喜欢的是 “_”

image

参考自:http://zhidao.baidu.com/question/329196001.html

6 :金子般的table

有很多人都不喜欢table,所以才有了div without table. 对于这些人来说table是不需要的,div 是神。

我以前写过一篇文章:你也可以的,Div Without Table

早这篇文章中,我使用div来布局,虽然题目叫做Div Without Table ,但是我并不是想表达Table 是没用的,Table 是应该被Without 的,我始终坚信一个原则“div 布局,table 展示数据”。

为什么table 是金子呢?

首先table 是一个很早就出现的元素,而且由于table 比较简单,所以各个浏览器对table 的渲染 大部分都是一致的,所以使用table你很容易实现一些功能。

a:居中显示

在有些时候居中显示会让你比较郁闷,你会感觉到table 的好用和舒服。

b:n行n列

对于几行几列的这种布局,不要怀疑,不要犹豫,使用table吧。

c:某些让你改bug 很郁闷的地方。

有时候你会发现你调来调去总是调不好,如果这个bug 引入table 的代价比较小的话,个人也推荐使用table。

 

传说div 比table 渲染的要快,因为table 必须得等到</table> ,table 中的元素才会被渲染出来,我没有测试过,不知道是不是这样。

 

7:使用一些CSS 框架

如果你的页面可以使用一些CSS框架的话,那就尝试使用一款CSS框架吧,960grid, blueprint 应该都还算可以。

[原创]ASP.NET MVC多域名多站点解析问题

mikel阅读(1027)

原有的一个ASP.NET MVC的项目只是一个域名建站点指向,现在由于项目大了,需要拆分成三个独立域名站点分别指向不同的首页,但是程序是一套程序,问题出来了,首页怎么指向的问题,于是看到Global.asax里面的routing规则,发现可以根据初始化访问的不同域名设置不同的默认首页,然后每个域名建立一个默认页面里面重定向到各自的首页,然后IIS中建立三个站点分别将默认页面设置为各自的重定向页面,不再只是用Default.aspx页面了,问题解决。

其实很多时候问题不一定要解决得那么华丽,实用即可!

Global.asax代码如下:

 String HostName = HttpContext.Current.Request.Url.Host.ToString().ToLower(); //获取URL主机地址
  if (HostName.IndexOf("mikel") >= 0)
  {
            routes.MapRoute(
                "Default",                                              // Route name
                "{controller}/{action}/{id}",                           // URL with parameters
                new { controller = "Home", action = "Index", id = "" }  // Parameter defaults
            );
   }
  if (HostName.IndexOf("kiwing") >= 0)
  {
            routes.MapRoute(
                "Default",                                              // Route name
                "{controller}/{action}/{id}",                           // URL with parameters
                new { controller = "User", action = "Index", id = "" }  // Parameter defaults
            );
   }

Default.aspx.cs页面代码:

 public void Page_Load(object sender, System.EventArgs e)
{
Response.Redirect("~/Home/Index/");
}

KiwingIndex.aspx.cs页面代码:

 public void Page_Load(object sender, System.EventArgs e)
{
Response.Redirect("~/User/Index/");
}

[转载]Android模拟器连接物理键盘

mikel阅读(921)

[转载]Android模拟器连接物理键盘 – 范长法@三月软件 – 博客园.

  在Android模拟器中测试的时候,经常需要向譬如EditText中输入数据,Android模拟器键盘输入方式有三种:

1. Android系统自带的虚拟键盘,点击文本框时出现:

2. Android虚拟机左边的可视虚拟键盘:

3.我们使用电脑的物理键盘。

 

刚开始测试时,每次都需要用鼠标在模拟器上的屏幕上像傻瓜一样乱点,用了一天中午受不了了,摸索了一番,终于发现原来Android设置虚拟机支持物理键盘的时候是需要在建模拟器时指定。

下面是在新建虚拟机或Edit虚拟机的界面:

 

添加上面两项:

keyboard lid support: 模拟器物理键盘,设为yes,表示模拟器物理键盘可用;

keyboard support : 电脑键盘,设为yes,电脑键盘可用。

 

这样就ok了,呵呵,用物理键盘真的很爽。以后搞开发还是需要先把编译器熟悉熟悉一下,这样可以提高效率。不要只是因为一时的懒不想去摸索。搞计算机的勤快还是必须的。

[转载]以防万一,把被删除的数据都备份起来

mikel阅读(987)

[转载]以防万一,把被删除的数据都备份起来,关键数据丢了哭都来不及了 – 通用信息化建设平台 – 博客园.

防止误删除有目前通用权限管理里有2个方法,1个是打删除标志,另外一个把数据备份到另外一个表里,这个看开发人员的选择,觉得哪个做法好,就可以用哪个方法,删除标志的方法虽然简单,但是过滤数据很麻烦,而且数据库量大后数据库的性能有明显的影响。

备份到另外一个表,虽然程序处理繁杂一些,但是数据库的性能映像很小,有对数据洁癖的人适合用这个方式。下面是例子程序,可以模仿通用权限管理把自己的业务系统都进行改造,思路思想也都可以借鉴一下。

总算有心情写个博客了,被删除的数据若有需要恢复过来,不是专业的数据库管理员,那是一个很难的事情,而且知道哪些数据被删除了,也不是那么 简单的事情,写个触发器是一个不错的处理方法,把当前要被删除的数据,都存放早相同结构的另外一个表里。 相对自增量而言GUID为主键的处理起来更简单了。

通用权限管理,吉日嘎拉

被删除的表,主键最好不是自增量,因为需要保留原始数据的主键,否则数据库很难恢复或者涉及到主细表的问题等等,所以被删除的表的主键建议不要用则增量。

通用权限管理,吉日嘎拉

我们在角色管理界面上选中2条数据库,在调试模式下,然后按删除,看程序的运行效果如何?

通用权限管理,吉日嘎拉

已经被放到被删除的表里来了,主键也没被篡改,非常不错。

通用权限管理,吉日嘎拉

这个是为了特意在测试调试模式下把被删除的数据转移到另外一个表的做法。

通用权限管理,吉日嘎拉

 

下面是没有采用数据库触发器的方式,对删除的表进行数据备份的方法。

1:这里设计到备份表的主键问题。

2:数据库事务问题,要么成功,要么失败,要么全成功。

3:不要数据库触发器,而是用程序去实现。

4:兼容多种数据库。

5:下出来的代码量非常小,不能有过于繁琐的代码,需要重复利用很多现有的类库。

6:由于系统同时支持多个子系统,意思是有可能是多个系统的不同的角色表,所以要支持多系统的权限管理说白了就是多表的操作,不只是固定的2个表。

/// <summary>
        /// 批量删除角色
        /// </summary>
        /// <param name="userInfo">用户</param>
        /// <param name="ids">主键数组</param>
        /// <returns>影响行数</returns>
        public int BatchDelete(BaseUserInfo userInfo, string[] ids)
        {
            // 写入调试信息
            #if (DEBUG)
                int milliStart = BaseBusinessLogic.StartDebug(userInfo, MethodBase.GetCurrentMethod());
            #endif

            // 加强安全验证防止未授权匿名调用
            #if (!DEBUG)
                LogOnService.UserIsLogOn(userInfo);
            #endif

            int returnValue = 0;
            using (IDbHelper dbHelper = DbHelperFactory.GetHelper(BaseSystemInfo.UserCenterDbType))
            {
                try
                {
                    dbHelper.Open(UserCenterDbConnection);
                    // 开始数据库事务
                    dbHelper.BeginTransaction();
                    string tableName = BaseRoleEntity.TableName;
                    if (!string.IsNullOrEmpty(BaseSystemInfo.SystemCode))
                    {
                        tableName = BaseSystemInfo.SystemCode + "Role";
                    }
                    BaseRoleManager roleManager = new BaseRoleManager(dbHelper, userInfo, tableName);
                    // 这里是直接删除功能的实现
                    // returnValue = roleManager.BatchDelete(ids);

                    BaseRoleEntity roleEntity = null;
                    // 把删除的记录放到被删除的表里(表名后面加了后缀Deleted,也可以放在另外一个数据库里也可以的)
                    BaseRoleManager roleDeletedManager = new BaseRoleManager(dbHelper, userInfo, tableName + "Deleted");
                    foreach (var id in ids)
                    {
                        // 逐个删除,逐个备份
                        roleEntity = roleManager.GetEntity(id);
                        // 先添加到被删除的表里,这时候原先数据的主键需要保留的,否则恢复数据时可能会乱套
                        roleDeletedManager.Add(roleEntity);
                        // 数据备份好后再进行删除处理
                        returnValue += roleManager.Delete(id);
                    }
                    // 提交数据库事务
                    BaseLogManager.Instance.Add(dbHelper, userInfo, serviceName, AppMessage.RoleService_BatchDelete, MethodBase.GetCurrentMethod());
                    dbHelper.CommitTransaction();
                }
                catch (Exception ex)
                {
                    // 撤销数据库事务
                    dbHelper.RollbackTransaction();
                    BaseExceptionManager.LogException(dbHelper, userInfo, ex);
                    throw ex;
                }
                finally
                {
                    dbHelper.Close();
                }
            }

            // 写入调试信息
            #if (DEBUG)
                BaseBusinessLogic.EndDebug(MethodBase.GetCurrentMethod(), milliStart);
            #endif

            return returnValue;
        }

通用权限管理系统的架构,几乎没修改几行代码,就可以实现用户的删除数据是备份数据的需求,虽然没数据库触发器处理那么简单,但是程序的灵活性很强,可阅读性、可调试性、多数据库的兼容性等等方面,还是有明显的优点的。

删除处理的方法还可以写在代码生成器里,这样所有的删除操作,都可以实现数据库的备份了,又简单又好用,也不用动脑子了,很省事。

将权限管理、工作流管理做到我能力的极致,一个人只能做好那么很少的几件事情。

[转载]多站点Session共享解决方案

mikel阅读(1005)

[转载]多站点Session共享解决方案 – 杰之蓝 – 博客园.

对于大多数的网站来说,都会使用Session来维护用户在一次会话中操作;Session对于任何Web项目来说都是必不可少的(当然除去那 里网站里不包含任何用户操作的,^_^这个对于Web2.0时代的网站来说好像是不太可能的吧)。对于单独的站点来说,一个站点只用一个Session就 OK了,但对于同时多个站点来说,如何对多个站点时实现Session共享呢?

常见的作法有:

  • 使用Cookie方式实现多个站点间的共享(这种方式只限于几个站点都在同一域名的情况下);
  • 使用.net自动的状态服务(ASP.NET State Service);
  • 使用.net的Session数据库;
  • 使用MemcachedDB。

以上几种方案各有优点,至于每种方式的优点在那里,缺点在那里?一时半会真的很难说清,如果有一篇文章就能说清的,那都是扯蛋,这种东西没有在实际中使用,单单在表现上说这个方案好那个方案不好,都是扯蛋。

我们的项目现在采用的是第三种方案,使用Session数据库解决多站点的Session共享。有不同看法的朋友都可以聊一下,下面说一下我们的实现方式:

  1. 既然使用Session数据库了,当然必须要先对数据库进行创建,既然是使用微软的方案了,微软肯定也就为大家提供了相应的实现方式。通过命令行方式进入:
    1 C:\Windows\Microsoft.NET\Framework64\v4.0.30319

    在此目录下运行:

    1 aspnet_regsql.exe -sstype c -ssadd -d 你的数据库名 -U 用户名 -P 密码 -S 数据库服务地址

    注意:此处的参数是区分大小写的;执行完上述命令后,会进行Session数据库创建阶段,创建完成后可以打开数据库查看创建是否成功。

  2. Session数据库创建成功了并不代表就可以实现多项目的Session共享了,还需要对目前的Session数据库做一些小小的手脚,其实就是为了欺骗数据库说“哎,我就一个应用程序在运行。^_^”。下面来看看怎么做这点小手段:
ALTERPROCEDURE[dbo].[TempGetAppID]
@appName    tAppName,
@appIdint OUTPUT
AS
SET@appName=LOWER(@appName)
SET@appId=NULL

SELECTtop1@appId= AppId
FROM[SNSSessionDB].dbo.ASPStateTempApplications
--WHERE AppName = @appName

IF@appIdISNULLBEGIN
BEGINTRAN

SELECT@appId= AppId
FROM[SNSSessionDB].dbo.ASPStateTempApplications WITH (TABLOCKX)
WHERE AppName =@appName

IF@appIdISNULL
BEGIN
EXEC GetHashCode @appName, @appId OUTPUT

INSERT[SNSSessionDB].dbo.ASPStateTempApplications
VALUES
         (@appId, @appName)

IF@@ERROR=2627
BEGIN
DECLARE@dupApp tAppName

SELECT@dupApp=RTRIM(AppName)
FROM[SNSSessionDB].dbo.ASPStateTempApplications 
WHERE AppId =@appId

RAISERROR('SQL session state fatal error: hash-code collision between applications ''%s'' and ''%s''. Please rename the 1st application to resolve the problem.', 
, 1, @appName, @dupApp)
END
END

COMMIT
END

RETURN0

其实只是做了一点改动,就是加了一个top 1 ,我每次查的时候,只能第一次的AppID这样的话,就是说我多个项目只一个Session实例。

上面的各种手段都做了,其实目的只有一个就是在项目中使用这个Session数据库(发点牢骚:说微软坑爹吧,其实一点都不假,他啥都替你想到了,我们这只简单的会使用他就行了,这也是一代一代.NET开发人员的悲剧,每次微软发生新的技术改动,我们这些苦逼的开发人员就要去学习学习,然后微软突然那天说我不对这个技术再做升级了,我要放弃他了,好了你就看吧,大街上一个个苦着脸的,有一半都是搞开发的。)。怎么在项目中使用他呢?修改 web.config 在system.web 加入或修改以下项

1
2  

  4. OK,你大功告成了.记得重启一下IIS ,最好把自己本机上的cookie或垃圾项清除一下,这样效果更好。

  通过上面的一系列操作,终于OK了,在项目中使用的时候,就像我们平常一样赋值和调用就OK了。

  OK了,终于写完了。

[转载]ASP.NET MVC的View是如何呈现出来的[实例篇]

mikel阅读(995)

[转载]ASP.NET MVC的View是如何呈现出来的[实例篇] – Artech – 博客园.

在《[设计篇]》篇中我们通过对View引擎的总体介绍讲述了从ViewResult的创建到View呈现的原理,为了让读者对View引擎及其View呈现机制具有一个深刻的认识,我们自定义一个简单的用于呈现静态HTML的StaticFileViewEngine。 在一个通过Visual Studio的ASP.NET MVC项目模板创建的空Web应用中,我们定义了如下一个针对于静态HTML内容呈现的自定义StaticFileView。 StaticFileView实现了IView接口,在实现的Render方法中读取制定文件的内容写入作为参数的TextWriter。 [本文已经同步到《How ASP.NET MVC Works?》中]

1: public class StaticFileView:IView

2: {

3: public string FileName { get; private set; }

4: public StaticFileView(string fileName)

5: {

6: this.FileName = fileName;

7: }

8: public void Render(ViewContext viewContext, TextWriter writer)

9: {

10: byte[] buffer;

11: using (FileStream fs = new FileStream(this.FileName, FileMode.Open))

12: {

13: buffer = new byte[fs.Length];

14: fs.Read(buffer, 0, buffer.Length);

15: }

16: writer.Write(Encoding.UTF8.GetString(buffer));

17: }

18: }

由于StaticFileView中定义的内容完全是静态的,所以缓存显得很有必要。我们只需要基于Controller和View名称对View实施缓存,为此我们定义了如下一个作为Key的数据类型ViewEngineResultCacheKey。

1: internal class ViewEngineResultCacheKey

2: {

3: public string ControllerName { get; private set; }

4: public string ViewName { get; private set; }

5:

6: public ViewEngineResultCacheKey(string controllerName, string viewName)

7: {

8: this.ControllerName = controllerName ?? string.Empty;

9: this.ViewName = viewName ?? string.Empty;

10: }

11: public override int GetHashCode()

12: {

13: return this.ControllerName.ToLower().GetHashCode() ^ this.ViewName.ToLower().GetHashCode();

14: }

15:

16: public override bool Equals(object obj)

17: {

18: ViewEngineResultCacheKey key = obj as ViewEngineResultCacheKey;

19: if (null == key)

20: {

21: return false;

22: }

23: return key.GetHashCode() == this.GetHashCode();

24: }

25: }

具有如下定义的StaticFileViewEngine代表StaticFileView对应的ViewEngine。我们通过一个字典类型的字段viewEngineResults作为对ViewEngineResult的缓存,而View的获取操作最终实现在InternalFindView方法中。通过StaticFileView表示的View定义在一个以View名称作为文件名的文本文件中,该文件的扩展名为.shtml(Static HTML)。

1: public class StaticFileViewEngine : IViewEngine

2: {

3: private DictionaryviewEngineResults = new Dictionary();

4: private object syncHelper = new object();

5: public ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache)

6: {

7: return this.FindView(controllerContext, partialViewName, null, useCache);

8: }

9:

10: public ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)

11: {

12: string controllerName = controllerContext.RouteData.GetRequiredString("controller");

13: ViewEngineResultCacheKey key = new ViewEngineResultCacheKey(controllerName, viewName);

14: ViewEngineResult result;

15: if (!useCache)

16: {

17: result = InternalFindView(controllerContext, viewName, controllerName);

18: viewEngineResults[key] = result;

19: return result;

20: }

21: if(viewEngineResults.TryGetValue(key, out result))

22: {

23: return result;

24: }

25: lock (syncHelper)

26: {

27: if (viewEngineResults.TryGetValue(key, out result))

28: {

29: return result;

30: }

31:

32: result = InternalFindView(controllerContext, viewName, controllerName);

33: viewEngineResults[key] = result;

34: return result;

35: }

36: }

37:

38: private ViewEngineResult InternalFindView(ControllerContext controllerContext, string viewName, string controllerName)

39: {

40: string[] searchLocations = new string[]

41: {

42: string.Format( "~/views/{0}/{1}.shtml", controllerName, viewName),

43: string.Format( "~/views/Shared/{0}.shtml", viewName)

44: };

45:

46: string fileName = controllerContext.HttpContext.Request.MapPath(searchLocations[0]);

47: if (File.Exists(fileName))

48: {

49: return new ViewEngineResult(new StaticFileView(fileName), this);

50: }

51: fileName = string.Format(@"\views\Shared\{0}.shtml", viewName);

52: if (File.Exists(fileName))

53: {

54: return new ViewEngineResult(new StaticFileView(fileName), this);

55: }

56: return new ViewEngineResult(searchLocations);

57: }

58:

59: public void ReleaseView(ControllerContext controllerContext, IView view)

60: { }

61: }

在InternalFindView中,我们先在“~/Views/{ControllerName}/”目录下寻找View文件,如果不存在则在“~/Views/Shared/”寻找。如果对应View文件被找到,则以此创建一个StaticFileView对象,并最终返回封装该View对象的ViewEngineResult。如果目标View文件找不到,则根据基于这两个目录的搜寻地址列表创建并返回对应的ViewEngineResult。 现在我们在Global.asax通过如下的代码对自定义的StaticFileViewEngine进行注册,我们将创建的StaticFileViewEngine作为第一个使用的ViewEngine。

1: public class MvcApplication : System.Web.HttpApplication

2: {

3: protected void Application_Start()

4: {

5: //其他操作

6: ViewEngines.Engines.Insert(0, new StaticFileViewEngine());

7: }

8: }

然后我们定义了如下一个简单的HomeController,Action方法ShowNonExistentView中通过调用View方法呈现一个不存在的View(NonExistentView),而ShowStaticFileView方法则将对应的StaticFileView呈现出来。

1: public class HomeController : Controller

2: {

3: public ActionResult ShowNonExistentView()

4: {

5: return View("NonExistentView");

6: }

7:

8: public ActionResult ShowStaticFileView()

9: {

10: return View();

11: }

12: }

我们为Action方法ShowStaticFileView创建一个StaticFileView类型的View文件ShowStaticFileView.shtml(该View文件保存在“~/Views/Home”目录下,扩展名不是.cshtml,而是shtml),其内容就是如下一段完整的HTML。

1:

2:

3:

4:Static File View

5:

6:

7: 这是一个自定义的StaticFileView!

8:

9:

现在运行我们的程序,在浏览器中输入相应的地址访问Action方法ShowNonExistentView,会得到如下图所示的输出结果。图中列 出的View搜寻位置列表中的前两项正是我们自定义的StaticFileViewEngine寻找对应.shtml文件的两个地址。

 

image

 

如果我们改变浏览器的地址来访问另一个Action方法ShowStaticFileView,会呈现出如下图所示的输出结果,不难看出呈现出来的正是定义在ShowStaticFileView.shtml中的HTML。

 

image

ASP.NET MVC的View是如何被呈现出来的?[设计篇]

[转载]easyui datagrid批量提交json数据到服务器

mikel阅读(1294)

[转载]easyui datagrid 批量 提交 json 数据到服务器 – 管宇 – 博客园.

1. 涉及到的技术。

ASP.NET mvc 3.0.

JQuery,  JQuery easyui datagrid.

JQuery-json – 把js对象,生成json格式的插件 (http://code.google.com/p/jquery-json/ )

 

2. 场景。

我们知道由datagrid编辑后生成的数据是js对象。 这样我们提交到服务器,是无法解析的(如果你有好的方式,请在下面评论,ths)。所以需要解析为json.

 

datagrid  生成json :

var table = $("#table_directory").datagrid("getRows");

var obj = "[";

for (var i = 0; i < table.length; i++) {

     $('#table_directory').datagrid("endEdit", i);

     obj += $.toJSON(table[i]);

     if (i != table.length - 1) {
        obj += ",";
     }
}

obj += "]";

服务器解析json:
JavaScriptSerializer JavaScriptSerializer = new JavaScriptSerializer();
List listSectionBase = javaScriptSerializer.Deserialize(jsonChapter, typeof(List)) as List;
SectionBase 这个类不用管。

是你自己的类即可,哪怕服务器端的属性和前端提交的不一致,也没有问题。 这样数据已经到了服务器,自己就可以继续进行服务器操作了。

[转载]通过一个模拟程序让你明白ASP.NET MVC是如何运行的

mikel阅读(853)

[转载]通过一个模拟程序让你明白ASP.NET MVC是如何运行的 – Artech – 博客园.

ASP.NET MVC的路由系统通过对HTTP请求的解析得到表示Controller、Action和其他相关的数据,并以此为依据激活Controller对象,调 用相应的Action方法,并将方法返回的ActionResult写入HTTP回复中。为了更好的演示其实现原理,我创建一个简单的ASP.NET Web应用来模拟ASP.NET MVC的路由机制。这个例子中的相关组件基本上就是根据ASP.NET MVC的同名组件设计的,只是我将它们进行了最大限度的简化,因为我们只需要用它来演示大致的实现原理而已。[源代码从这里下载]

目录:
一、一个通过查询字符串表示Controller和Action的“MVC”程序
二、通过Route解析HTTP请求获得路由信息
三、在Global.asax中注册Route
四、Route的执行
五、通过MvcHandler处理请求
六、将ActionResult写入Http回复
七、实例的配置和定义

一、一个通过查询字符串表示Controller和Action的“MVC”程序

image

如 右图所示,我们的Web应用非常简单。HomeController.cs为定义Controller类型的文件,而Index.html表示 HomeController中名称为Index的Action对应的View。我们按照ASP.NET MVC的原理,通过解析请求URL得到Controller和Action的名称。如果Controller为Home,则激活 HomeController,如果当前的Action为Index,则将Index.html这个静态文件的内容作为HTTP回复返回。

我不想定义复杂的解析Controller和Action的逻辑,再这里我直接通过请求URL相应的查询字符串controler和action表示Controller和Action的名称。也就是说如果通过浏览器访问地址http://localhost/mvcapp/?controller=Home&action=Index 可以访问到Index.html中的内容(注:我们并没有将Index.html作为站点的默认页面)。

image

接下来我简单的介绍一下是哪些组建促使这个简单的ASP.NET Web应用能够按照MVC的模式来执行。为了使你能够在真正的ASP.NET MVC找到匹配的组件,我们采用了相同的接口和类型名称。

二、通过Route解析HTTP请求获得路由信息

我 定义了如下一个RouteData类型表示解析HTTP请求得到的Controller和Action等信息。Assemblies和 Namespaces表示需要引入的命名空间和程序集,这是因为URL中只能解析出Controller的类型名称,需要相应的命名空间采用得到它的类型 全名。如果对应的程序集不曾加载,还需要加载相应的程序集。

   1: public class RouteData

   2: {

   3:     public string Controller { get; set; }

   4:     public string Action { get; set; }

   5:     public IList<string> Assemblies { get; private set; }

   6:     public IList<string> Namespaces { get; private set; }

   7:     public IRouteHandler RouteHandler { get; set; }

   8:  

   9:     public RouteData(string controller, string action, IRouteHandler routeHandler)

  10:     {

  11:         this.Controller = controller;

  12:         this.Action = action;

  13:         this.RouteHandler = routeHandler;

  14:         this.Namespaces = RouteTable.Namespaces;

  15:         this.Assemblies = RouteTable.Assemblies;

  16:     }

  17: }

真正实现对HTTP请求进行解析并得到RouteData的Route继承自基类RouteBase。我们还定义个了一个表示Route集合的RouteCollection类型,它的GetRouteData方法对集合的所有Route对象进行遍历,并调用其GetRouteData方法。如果得到的RouteData不为空,则返回之。

   1: public abstract class RouteBase

   2: {

   3:     public abstract RouteData GetRouteData(HttpContextBase httpContext);

   4: }

   5:  

   6: public class RouteCollection: Collection<RouteBase>

   7: {

   8:     public RouteData GetRouteData(HttpContextBase httpContext)

   9:     {

  10:         foreach (RouteBase route in this)

  11:         {

  12:             var routeData = route.GetRouteData(httpContext);

  13:             if (null != routeData)

  14:             {

  15:                 return routeData;

  16:             }

  17:         }

  18:         return null;

  19:     }

  20: }

和ASP.NET MVC一样,我们定义了如下一个RouteTable对象,其静态属性正是一个RouteCollection对象。两个静态属性Namespaces和Assemblies为命名空间和程序集名称的全局维护。

   1: public class RouteTable

   2: {

   3:     static RouteTable()

   4:     {

   5:         Routes = new RouteCollection();

   6:         Namespaces = new List<string>();

   7:         Assemblies = new List<string>();

   8:     }

   9:     public static RouteCollection Routes { get; private set; }

  10:     public static IList<string> Namespaces { get; private set; }

  11:     public static IList<string> Assemblies { get; private set; }

  12: }

而我们实例中完成基于查询字符串的Controller和Action解析的QueryStringRoute对应如下。在GetRouteData方法中,除了根据查询字符解析并初始化Controller和Action名称之外,还将RouteHandler指定为MvcRouteHandler。而MvcRouteHandler得GetHttpHandler方法直接返回的是根据RequestContext创建的MvcHandler对象。



   1: public class QueryStringRoute : RouteBase

   2: {

   3:     public override RouteData GetRouteData(HttpContextBase httpContext)

   4:     {

   5:         if (httpContext.Request.QueryString.AllKeys.Contains("controller") &&

   6:             httpContext.Request.QueryString.AllKeys.Contains("controller") )

   7:         {

   8:             string controller = httpContext.Request.QueryString["controller"];

   9:             string action = httpContext.Request.QueryString["action"];

  10:             IRouteHandler routeHandler = new MvcRouteHandler();

  11:             return new RouteData(controller, action, routeHandler);               

  12:         }

  13:         return null;

  14:     }

  15: }

  16:  

  17: public class MvcRouteHandler: IRouteHandler

  18: {

  19:     public IHttpHandler GetHttpHandler(RequestContext requestContext)

  20:     {

  21:         return new MvcHandler(requestContext);

  22:     }

  23: }

三、在Global.asax中注册Route

通过上面定义的RouteTable类型,我们在Global.asax中按照如下的方式在应用启动的时候QueryStringRoute对象添加到RouteTable的静态属性Routes表示的Route列表中。同时为需要的命名空间和程序集名称进行初始化,以辅助后续步骤中对Controller的创建。

   1: public class Global : System.Web.HttpApplication

   2: {

   3:     protected void Application_Start(object sender, EventArgs e)

   4:     {

   5:         RouteTable.Routes.Add(new QueryStringRoute());

   6:         RouteTable.Assemblies.Add("MvcApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null");

   7:         RouteTable.Namespaces.Add("Artech.MvcApp");

   8:     }

   9: }

四、Route的执行

通过RouteTable的Routes属性表示的Route列表对请求的解析和路由信息的获取是通过自定义的HttpModule来实现的,它的类型为UrlRoutingModule。如下面的代码片断所示,UrlRoutingModule注册了HttpApplication的PostResolveRequestCache事件,并在该事件触发的时候调用Route列表的GetRouteData方法,并根据得到RouteData创建RequestContext。最后通过RouteData的RouteHandler得到真正用于处理该请求的HttpHandler对象,并对其进行映射。这意味着后续将会采用这个映射的HttpHandler进行请求的处理。

   1: public class UrlRoutingModule: IHttpModule

   2: {

   3:     public void Dispose() { }

   4:     public void Init(HttpApplication context)

   5:     {

   6:         context.PostResolveRequestCache += (sender, args) =>

   7:             {

   8:                 HttpContextWrapper contextWrapper = new HttpContextWrapper(context.Context);

   9:                 HttpContextBase httpContext = (HttpContextBase)contextWrapper;

  10:                 RouteData routeData = RouteTable.Routes.GetRouteData(httpContext);

  11:                 if (null == routeData)

  12:                 {

  13:                     return;

  14:                 }

  15:                 RequestContext requestContext = new RequestContext { HttpContext = httpContext, RouteData = routeData };                    

  16:                 httpContext.RemapHandler(routeData.RouteHandler.GetHttpHandler(requestContext));

  17:             };

  18:     }

  19: }

五、通过MvcHandler处理请求

在UrlRoutingModule映射的实际上是具有如下定义的MvcHandler,它具有一个RequestContext属性通过构造函数进行初始化。在ASP.NET MVC中,真正的请求处理体现在根据路由信息创建Controller,并执行相应的Action方法。这两个步骤体现的ProcessRequest方法中。

   1: public class MvcHandler: IHttpHandler

   2: {

   3:     public RequestContext RequestContext{get; private set;}

   4:     public IControllerFactory ControllerFactory

   5:     {

   6:         get { return ControllerBuilder.Current.GetControllerFactory(); }

   7:     }

   8:     public MvcHandler(RequestContext requestContext)

   9:     {

  10:         this.RequestContext = requestContext;

  11:     }

  12:     public bool IsReusable

  13:     {

  14:         get { return false; }

  15:     }

  16:     public void ProcessRequest(HttpContext context)

  17:     {

  18:         RouteData routeData = this.RequestContext.RouteData;

  19:         var controller =  this.ControllerFactory.CreateController(this.RequestContext, routeData.Controller);

  20:         controller.Execute(this.RequestContext);

  21:     }

  22: }

Controller实现了具有如下定义的接口IController,所有Action方法都通过Execute方法执行,该方法的参数的表示当前请求上下文的RequestContext对象。IController通过相应的Controller工厂创建,下面的代码同时也定义了Controller工厂接口的定义。

   1: public interface IController

   2: {

   3:     void Execute(RequestContext requestContext);

   4: }

   5: public interface IControllerFactory

   6: {

   7:     IController CreateController(RequestContext requestContext, string controllerName);

   8: }

我们定义了如下一个简单名称为DefaultController,它的Execute方法定义很简单:通过包含在RequestContext的RouteData得到当前的Action,并将它作为方法名得到相应的MethodInfo对象,滨个通过反射调用它得到一个ActionResult对象,最后执行ActionResult的ExecuteResult方法。该方法的参数是基于RequestContext创建的另一个上下文ControllerContext。

   1: public class DefaultController : IController

   2: {

   3:     public void Execute(RequestContext requestContext)

   4:     {

   5:         string action = requestContext.RouteData.Action;

   6:         MethodInfo method = this.GetType().GetMethod(action);

   7:         ActionResult result = (ActionResult)method.Invoke(this, null);

   8:         ControllerContext controllerContext = new ControllerContext

   9:         {

  10:             RequestContext = requestContext

  11:         };

  12:         result.ExecuteResult(controllerContext);

  13:     }

  14: }

我们定义了具有如下定义的Controller工厂类DefaultControllerFactory。创建Controller的逻辑也不复杂:通过RouteData表示的Controller名称得到相应的Controller类型,通过反射创建Controller对象。由于RouteData中只包含Controller的名称,所以需要通过命名空间和程序集的辅助才能解析出真正的类型。

   1: class DefaultControllerFactory : IControllerFactory

   2: {

   3:     public IController CreateController(RequestContext requestContext, string controllerName)

   4:     {

   5:         RouteData routeData = requestContext.RouteData;

   6:         string controllerType = string.Format("{0}Controller", controllerName);

   7:         IController controller;

   8:         controller = this.CreateControler(controllerType);

   9:         if (null != controller)

  10:         {

  11:             return controller;

  12:         }

  13:         foreach (string assembly in routeData.Assemblies)

  14:         {

  15:             controller = this.CreateControler(controllerType, assembly);

  16:             if (null != controller)

  17:             {

  18:                 return controller;

  19:             }

  20:  

  21:             foreach (string ns in routeData.Namespaces)

  22:             {

  23:                 controllerType = string.Format("{0}.{1}Controller", ns, controllerName);

  24:                 controller = this.CreateControler(controllerType, assembly);

  25:                 if (null != controller)

  26:                 {

  27:                     return controller;

  28:                 }

  29:             }

  30:         }

  31:  

  32:         throw new InvalidOperationException("Cannot locate the controller");

  33:     }

  34:     private IController CreateControler(string controllerType, string assembly = null)

  35:     {

  36:         Type type = null;

  37:         if (null == assembly)

  38:         {

  39:             type = Type.GetType(controllerType);

  40:         }

  41:         else

  42:         {

  43:             type = Assembly.Load(assembly).GetType(controllerType);

  44:         }

  45:         if (null == type)

  46:         {

  47:             return null;

  48:         }

  49:         return Activator.CreateInstance(type) as IController;

  50:     }

  51: }

六、将ActionResult写入Http回复

Controller的Action方法的返回值为具有如下定义的ActionResult类型,通过ExecuteResult方法将相应的执行结果写入HTTP回复中。我定义了如下一个StaticViewResult,它根据RouteData中的Action信息找到匹配的.html静态文件,并将文件的内容写入HttpResponse。

   1: public abstract class ActionResult

   2: {

   3:     public abstract void ExecuteResult(ControllerContext context);

   4: }

   5:  

   6: public class StaticViewResult: ActionResult

   7: {

   8:     public override void ExecuteResult(ControllerContext context)

   9:     {

  10:         context.RequestContext.HttpContext.Response.WriteFile(context.RequestContext.RouteData.Action + ".html");

  11:     }

  12: }

七、实例的配置和定义

在我们的实例中定义的HomeController定义如下,在表示Action的Index方法中,直接返回一个StaticViewResult对象。

   1: public class HomeController : DefaultController

   2: {

   3:     public ActionResult Index()

   4:     {

   5:         return new StaticViewResult();

   6:     }

   7: }

然后在配置中进行了针对UrlRoutingModule的注册,仅此而已。

   1: <configuration>

   2:   <system.webServer>

   3:     <modules>

   4:       <add name="UrlRoutingModule" type="Artech.MvcRouting.UrlRoutingModule, Artech.MvcRouting"/>

   5:     </modules>

   6:   </system.webServer>

   7: </configuration>