[转载]ASP.NET MVC3-RAZOR尝鲜2细说实用的WebGrid

mikel阅读(1078)

[转载]MVC3-RAZOR尝鲜2细说实用的WebGrid – 撞破南墙 – 博客园.

1WebGrid的方法签名

public WebGrid(

IEnumerable<dynamic> source, 设置数据源

IEnumerable<string> columnNames = null, 要显示的列名

string defaultSort = null, 默认排序的字段

int rowsPerPage = 10, 每页的行数

bool canPage = true, 是否允许分页

bool canSort = true, 是否允许排序

string ajaxUpdateContainerId = null,

string ajaxUpdateCallback = null,

string fieldNamePrefix = null,字段名的前缀

string pageFieldName = null,

string selectionFieldName = null,

string sortFieldName = null,

string sortDirectionFieldName = null);

代码

List<CMS5_Razor.Models.Test> list = new List<CMS5_Razor.Models.Test>();
for (int i = 0; i < 210; i++) {
list.Add(
new CMS5_Razor.Models.Test() { Name = name + i, Order = i, Content = content + i });
}
var grid
= new WebGrid(source: list, rowsPerPage: 5, canPage: true
, selectionFieldName:
Name
, fieldNamePrefix:
字段名的前缀
);

2WebGrid.GetHtml函数签名

public IHtmlString GetHtml(

string tableStyle = null,表格样式

string headerStyle = null,头部

string footerStyle = null, 底部

string rowStyle = null, 每一行的样式

string alternatingRowStyle = null, 交替行

string selectedRowStyle = null, 被选中

string caption = null,标题

bool displayHeader = true, 是否显示头部

bool fillEmptyRows = false, 是否填充空行

string emptyRowCellValue = null, 空行里每个字段显示的值

IEnumerable<WebGridColumn> columns = null, 在这里设置各列

IEnumerable<string> exclusions = null, 不显示的字段

WebGridPagerModes mode =枚举值,一般情况选择WebGridPagerModes.All

string firstText = null, 对应第一页链接显示的文字

string previousText = null, 对应上一页链接显示的文字

string nextText = null, 对应下一页链接显示的文字

string lastText = null, 对应最后一页链接显示的文字

int numericLinksCount = 5,数字选择项的数目

object htmlAttributes = null  ~beta版本源码中没查到,暂时不知道如何使用,

);

3Column的方法签名

public WebGridColumn Column(string columnName = null,

string header = null,列头的名字

Func<dynamic, object> format = null,  自定义的输出,非常实用

string style = null, 样式

bool canSort = true);是否允许排序

@grid.GetHtml(
columns: grid.Columns(
grid.Column(
Name, 名字, style: mynameStyle),
grid.Column(
Content, Content, style: mynameStyle),
grid.Column(
Order, 顺序, format: @<b><i>@item.Order</i></b>, canSort: false)
), tableStyle:
grid, headerStyle: headerStyle1, selectedRowStyle: selectedRowStyle,
caption:
我是标题, displayHeader: !IsPost,
fillEmptyRows:
!IsPost, emptyRowCellValue: 这行没东西,
mode: WebGridPagerModes.All, firstText:
第一页,
previousText:
上一页, nextText: 下一页, lastText: 最后一页,
numericLinksCount:
15
)

效果

我的感受:

1  功能非常多。常用的基本上都包括了。 包括分页和排序。

2  似乎之前MVC2的时候是没有辅助生产表格的。而且之前开源社区提供的contribute库也没有这个好用。

3  RAZOR为我们做了太多了,太方便了!新手慎用!

4 还有一些特性如 ajaxUpdateContainerId,htmlAttributes  没有使用,也不好说。

[转载]深入浅出Flex Viewer 2.1(一)概述

mikel阅读(973)

[转载]深入浅出Flex Viewer 2.1(一)——概述 – enjoyInGIS-智慧点亮生活 – 博客园.

一、Flex Viewer简介

Flex Viewer是ESRI公司推出的可以高效开发基于WEB的地理信息应用系统的一种完全免费的应用程序框架。业务人员使用该框架可以无需任何额外的编程就 能够通过简单配置的方法快速搭建起一个基于ArcGIS Server的、以地图为中心的富客户端(RIA)应用的原型。该框架中还自带了大量的能够满足各种地图应用需要的Widget,如Identify、 GeoRSS、DataExtract、BookMark、NetworkAnalyst、MapSwitcher等地图交互和分析等工具。同时,如果需 要增加新的Widget,则开发人员只需在自定义的Widget中实现框架要求的接口,然后再将该Widget配置到框架中的Config.xml文件 中,就能在无需修改框架代码的情况下轻松地完成独立Widget与框架的无缝集成。框架运行界面如下图所示:

image

图1 运行界面

二、Flex Viewer实例的运行周期

Flex Viewer是基于Adobe公司推出的Flex开发出来的典型的Flex应用,它拥有和其它所有Flex应用程序相同的生命周期,即均由浏览器中 Flash Player进行加载和管理,如下所示步骤1。在Flex Viewer启动后,Flex Viewer会自动加载相应的配置文件,,并根据该文件中的各种配置项来初始化系统的功能、界面,以及加载和显示相关组件对应的flash文件(步骤 2)。接着,系统初始化地图窗口,并根据配置文件中配置的图层从运行于ArcGIS Server(也可为其它数据源,但需扩展)中获取地图数据(步骤3)。最后,系统根据配置信息及用户操作动态加载对应Widget相关的Flash文件 (步骤4),并在用户与该Widget交互的过程中向外部服务器获取数据和分析服务(步骤5)。

image

图2 实例的生命周期

三、Flex Viewer的价值

Flex Viewer这个框架的核心价值将程序员各种复杂的编程细节中解放了出来,如地图的管理、地图的浏览、应用的配置、内部组件的通信、数据的管理等。它允许 Web开发人员,特别是那些使用ESRI的ArcGIS技术的开发人员,能够得以专注于他们自定义的应用程序的核心业务功能的开发上。另外,也正是这个原 因,使得开发人员能够以配置的而非编程的方式将含有新功能的Widget快速地继承到已有的Flex Viewer框架中。

四、目标读者

1、使用Flex Viewer搭建原型的业务人员;

2、开发Flex viewer Widget组件的开发人员;

3、以及希望改造Flex Viewer已有框架的架构师等。

五、本系列的写作目的

由于Esri免费开放了Flex Viewer的源代码,所以开发人员可以对该框架拥有更细粒度的控制权。因此,笔者希望通过本系列文章向读者深入介绍该框架的架构和设计原理,以使得读者 能够全面、透明地掌握该框架,从而使其能够结合具体的业务需求以最简洁、最合理的方式对框架进行配置、开发或改造。

另外,由于本系列的定位主要是针对那些对Flex Viewer的使用有所了解,并希望进一步深入理解其内部设计原理的读者,所以Flex Viewer工程的配置,以及基本功能的使用,本文将不会涉及,请有需要的朋友查阅相关的帮助文档(http://help.arcgis.com/en/webapps/flexviewer/help/index.html)。

六、系列文章简介

该框架从2008年9月推出1.0版以来至今已近发展到了2.1版,本系列将针对当前最新的2.1版陆续推出另外六篇文章来向读者深入介绍Flex Viewer的设计原理:

1、在《深入浅出Flex Viewer 2.1(二)——体系结构》中,笔者从该框架的架构入手,深入依次介绍关键构件的设计原理和其相互关系,使读者能够对系统的架构拥有一个整体、清晰地理解;

2、在《深入浅出Flex Viewer 2.1(三)——Config的原理》中,笔者将介绍Config文件所支持的所有配置项,以及用于解析该配置项的构件,及其相应的设计原理和数据结构, 从而为读者对下篇《深入浅出Flex Viewer 2.1(四)——系统初始化的那些事儿》的理解作铺垫;

3、在《深入浅出Flex Viewer 2.1(四)——系统初始化的那些事儿》中,笔者将详细介绍从Flash Player加载系统对应Flash文件开始到系统初始化完成的全过程,读者通过这篇文章能够掌握系统在初始化的过程中涉及到了哪些构件、做了哪些事、如 何做到的,以及初始化后得到了哪些后期可重复利用的数据结构;

4、在《深入浅出Flex Viewer 2.1(五)——Widget的原理》中,笔者将深入介绍Widget的开发和其所需的关键抽象类和接口,以及Widget与框架能够无缝集成的原理;

5、在《深入浅出Flex Viewer 2.1(六)——如何增加新的数据源》中,笔者将以google map的底图数据作为新的数据源为例,向读者介绍数据源的扩展方法。

七、系列文章目录

《深入浅出Flex Viewer 2.1(一)——概述》

《深入浅出Flex Viewer 2.1(二)——体系结构》

《深入浅出Flex Viewer 2.1(三)——Config文件详解》

《深入浅出Flex Viewer 2.1(四)——系统初始化的那些事儿》

《深入浅出Flex Viewer 2.1(五)——Widget的原理》

《深入浅出Flex Viewer 2.1(六)——如何增加新的数据源》

[转载]深入浅出Flex Viewer 2.1(二)体系结构

mikel阅读(1145)

[转载]深入浅出Flex Viewer 2.1(二)——体系结构 – enjoyInGIS-智慧点亮生活 – 博客园.

一、概述

在上一篇文章《深入浅出Flex Viewer 2.1(一)——概述》中, 笔者对Flex Viewer用于构建以地图为中心的富客户端(RIA)应用的原型的功能和价值做了简要地介绍。在本文中,笔者将继续介绍该框架的体系结构。通过本文,读 者可以详细了解到Flex Viewer框架源代码的关键目录和文件结构,以及这些文件中所包含或涉及到的系统的哪些构件(第二章);以及这些构件间的逻辑关系和连接这些构件所用的 关键技术,如:消息总线(EventBus)、配置项管理(Config Manager)、数据共享机制(DataManager)的基本介绍(第三章)。

二、框架源码的结构视图

一般来说默认的Flex Viewer框架的源代码的结构如下图所示,其中目录结构图截取于Flash Builder 4.0,由于FB根据工程中目录和文件的语义将目录进行了逻辑上的重新组织,所以其可能与Flex Viewer实际的物理目录不一致:

image

图1 FB中的源代码目录

在源代码的根目录src下,存在4个子目录和3个文件,它们的功能分别是:

A、(默认包)

在目录下存在两个文件(FlexUnitCompilerApplication.mxml是FB自动生成的文件,可忽略),其中

1、index.mxml。它是整个框架的总入口,也就是说在运行时Flash Player也就是调用该文件所对应的flash文件来启动整个系统的;

2、defaults.css。它是整个系统的css样式表文件。

B、assets.image

该目录主要用于管理工程中的图片文件,工程中的其它文件可以通过相对路径的方式来访问其中的图片资源。

C、com.esri.viewer

该目录管理了Flex Viewer框架相关的所有核心代码,其中关键文件如下:

文件名 作用
AppEvent.as 定义了用于在消息总线(EventBus)中使用的消息类
BaseWidget.as 定义了Widget的基类,所有自定义的Widget均需继承该类
ConfigData.as 定义了系统在初始化时将config.xml文件中的配置项加载内存后,用于管理这些配置项的类型
IBaseWidget.as 定义了接口BaseWidget,同时类BaseWidget实现了该接口
IInfowindowTemplate.as 定义了接口InfowindowTemplate,所有自定义的InfoWindowTemplate均需实现该接口,同时自定义模板用于InfoWindow的窗口定义中。
IWidgetContainer.as 定义了接口IWidgetContainer,所有自定义的WidgetContainer均需实现该接口。WidgetContainer是用于管理Widget的一个可视化容易。
IWidgetTemplate.as 定义了接口IWidgetTemplate,所有自定义的WidgetTemplate均需实现该接口,同时自定义模板用于Widget的窗口定义中。
ViewerContainer.mxml 定义了可视化容器ViewerContainer,该容器是Flex Viewer中构件树的根
ConfigManager.as 定义了类configmanager,该类负责从config文件中加载兵解析全部配置信息,然后将这些信息存储于数据结构configData,最后通过触发事件AppEvent.CONFIG_LOADED将configData发布给其它组件使用
DataManager.as 定义了类DataManager,负责管理与维护系统内部的公共数据,使得系统中的各组件、Widget均能将公共数据发布到DataManager中或从其中获取其它组件发布的数据。
EventBus.as 继承了EventDispatcher接口,并使用单例模式向整个提供中的所有组件提供统一的消息注册和发布功能,从而使得各组件之间的完全做到低耦合、高内聚的效果
MapManager.mxml 负责根据config文件中的配置信息初始化地图控件、底图、optlayer,以及optlayer所对应的InfoWindowWidget, 并提供对事件SET_MAP_NAVIGATION(设置地图浏览工具)、BASEMAP_SWITCH(设置底图切换)、 SET_MAP_ACTION(设置绘图工具)、SHOW_INFOWINDOW(显示InfoWindow)、MAP_RESIZE(改变地图控件大 小)、DATA_OPT_LAYERS(请求OptLayersTable)、MAP_LAYER_VISIBLE(设置指定图层可见性)等的响应。
ScriptingManager.as 保留类,暂无特别用途
SecurityManager.as 保留类,暂无特别用途
UIManager.as 负责根据config文件中style的配置信息定义一套系统的UI样式表
WidgetManager.as 负责根据config文件的配置自动初始化Widget Container,及其包含的Widget控件,同时提供对事件WIDGET_RUN(打开Widget)、 DATA_CREATE_INFOWIDGET(创建OptLayer对应的InfoWindow)、WIDGET_FOCUS(设置Widget获得焦 点)、WIDGET_STATE_CHANGED(关闭Widget事件响应)的响应。

D、Widgets目录

该目录管理了系统中所有Widget的代码。

E、根目录下的config.xml文件

config.xml文件主要用于记录系统的配置项,以使得使用者能够在不修改框架代码的情况下来自定义系统的UI或功能。

三、构件的逻辑结构视图

在系统架构的逻辑结构上,框架大体上可分解为8个主要的架构元素:Viewer Container、Config Manager、UI Manager、Control Bar、Map Manager、Widget Manager、Data Manager,以及消息总线(EventBus)。它们之间的关系如下图所示:

image

图2 系统的架构图

其中该架构中存在着以下几个关键点:

A、消息总线

图中的Delegate即为消息总线(EventBus)。EventBus在整个系统中起到了至关重要的作用,即向整个系统中的所有组件提供统一的消息 注册和发布功能,所有构件均仅和EventBus进行交互,从而使得各组件之间的完全做到低耦合、高内聚的效果。

image

图3 消息总线与其它构件的交互

B、Viewer Container

Viewer Container是所有其它架构元素的根节点,它直接作为可视化控件嵌入到页面文件index.mxml中,如下index.mxml中的代码所示:

image

图4 index.mxml的代码

C、Config Manager

该类负责从config文件中加载兵解析全部配置信息,然后将这些信息存储于数据结构configData,最后通过向EventBus触发事件 AppEvent.CONFIG_LOADED将configData发布给其它构件使用。同时,其它任何向EventBus监听了该事件的构件(UI Manager、Map Manager、Widget Manager、Viewer Container等),均可自动调用相应的事件处理函数。

D、Data Manager

其内部运行原理主要是定义了一个用于存储公共数据的Hash表,并使用Singleton模式向整个系统提供数据发布和数据获取的服务,从而实现各构件间的数据共享。

四、我们在哪

通过本文,读者详细了解到Flex Viewer框架源代码的关键目录和文件结构,以及这些文件中所包含或涉及到的系统的哪些构件;以及这些构件间的逻辑关系和连接这些构件所用的关键技术, 如:消息总线(EventBus)、配置项管理(Config Manager)、数据共享机制(DataManager)的基本介绍。

那么在本系列下一篇文章《深入浅出Flex Viewer 2.1(三)——Config的原理》中,笔者将介绍Config文件所支持的所有配置项,以及用于解析该配置项的构件,及其相应的设计原理和数据结构, 从而为读者对《深入浅出Flex Viewer 2.1(四)——系统初始化的那些事儿》的理解作铺垫。

五、系列文章目录

《深入浅出Flex Viewer 2.1(一)——概述》

《深入浅出Flex Viewer 2.1(二)——体系结构》

《深入浅出Flex Viewer 2.1(三)——Config文件详解》

《深入浅出Flex Viewer 2.1(四)——系统初始化的那些事儿》

《深入浅出Flex Viewer 2.1(五)——Widget的原理》

《深入浅出Flex Viewer 2.1(六)——如何增加新的数据源》

[转载]苹果iPhone开发者计划注册流程

mikel阅读(1185)

[转载]苹果开发者计划注册流程 – 世上有一位全知全能的神,它会注视世人的一切,并且赐福给善良的人。 – 博客园.

最近正在研究 Android、iOS、Windows Phone 7 开发平台。先简单说说我对这三个平台的感想:做 Windows Phone 7 开发最爽,微软为开发者提供了最好的开发体验;iOS 也不错,但偶尔还是会被恶心一下下;Android 最完蛋,简单概况就是两个不行 —— 这也不行,那也不行。Android 本身简直一无是处,只不过是基于 Linux,有很多开源项目可用而已。如果你打算用 Java 在 Android 做开发,那你就会慢慢发现,Java 在 Android 上就是用来做 UI 的,根本什么都干不了。要在 Android 上做开发,还得用 C 来做。不过从头做成本太高,只好研究开源项目,再想办法移植到 Android 上。我举个例子,拿 Android 的 Media Framework和 Silverlight 的 Media Framework 做个对比。比如,要想让 Silverlight 支持 Apple 的 Http Live Streaming,只要用 C# 写一个 MPEG-TS 的分离器就可以了;同样,想让 Android 支持 Apple 的 Http Live Streaming,你会发现 Android 的 Media Framework 糟糕到极点,完全无法使用。你只能硬着头皮去从头慢慢研究 GStreamer 或 FFMpeg 这些开源项目,再想办法把这些项目移植到 Android 上。没错,你必须得自己移植一个 Media Framework 才可以!

如果想用 XCode 在  iPhone 上联机调试代码,那就要先注册成为苹果开发者,再加入苹果的 iOS 开发者计划。用 Google 搜一下会找到很多关于如何加入苹果的 iOS 开发者计划的文章,但是这些文章都是介绍以 Individual 名义加入开发者计划的步骤,没有一篇是介绍以 Company 名义加入开发者计划的流程。下面我就把我得到的经验分享出来,希望能对打算以 Company 名义加入开发者计划的朋友有所帮助 。

访问 http://developer.apple.com/programs/start/standard/ 页面,你会看到一个介绍加入苹果开发者计划的简单流程。

000

要加入苹果开发者计划得先注册一个 AppleID。注意,在注册 AppleID 时,务必用英文填写所有注册信息,否则在加入苹果开发者计划时个人信息会变成乱码。001

以 Individual 名义和 Company 名义加入苹果开发者计划的不同之处是,前者需要给苹果传真身份证扫描件,后者需要给苹果传真营业执照扫描件。这里选择以 Company 名义加入苹果开发者计划。

100

使用刚才注册的 AppleID 登录。

101

注意,填写公司信息时,务必用英文填写所有注册信息,否则在加入苹果开发者计划时公司信息会变成乱码。还需要注意的是,在填写公司名称时,务必填写 营业执照上的公司全称。比如“黑龙江省XXXX科技发展有限公司”,就填“Heilongjiang XXXX Technology Development Co., Ltd.”,千万别忘填“Heilongjiang”。

102

公司联系方式,想图省事可以不用填。

103

选择加入 iOS 开发者计划。

200

确认下注册信息是否正确,没问题就提交了。

300

提交注册信息之后,苹果会给你发送一封标题是“Thank You for Submitting Your Enrollment”邮件。再之后的48小时内,苹果还会再给你发送一封标题是“iOS Developer Program – EID XXXXXXXXXX”的邮件,里面有美国苹果总部的传真号码,需要你把营业执照的扫描件传真过去。注意,在传真营业执照扫描件之前,记得一定要在扫描件 最上方注明你的 Enrollment ID,不然苹果那边即使收到了传真也会对不上号的。还需要注意的是,如果遇到什么问题了,发邮件跟苹果沟通是没有用的,绝对的石沉大海。我建议你把要说的 打印出来(记得要在最上方注明你的 Enrollment ID),直接传真过去,这样才能尽快得到苹果的处理。

301

发完传真之后的48小时内,苹果的事务专员会打电话过来向你确认。给我打电话的是一位MM,操着一口纯正流利倍儿地道的印度东南部英语口音向我核 实。放下电话之后就会立即收到苹果发过来的一封标题是“Thank You for Joining an Apple Developer Program”的邮件。点击邮件里的“Log in now”按钮回到 Developer Member Center 就会发现已经通过审核到“Agree to License”流程了。

400

中国大陆只能用把信用卡信息用传真发过去才能完成支付。点击“Purchase Form”下载 PDF 文件,打印出来之后填好,再传真到苹果指定的传真号码。注意,以 Company 名义加入苹果开发者计划时,用谁的信用卡支付都可以。

image

再之后的48小时内,你会收到一封来自苹果标题是“Your Apple invoice # XXXXXXXXXX”的邮件,通知你已经完成支付了。再次回到 Developer Member Center 时,你会发现你的控制面板已经发生改变了。

611

621

622

631

632

苹果关于开发者计划角色的概述。

612

注意,以 Company 名义加入苹果开发者计划时,苹果不会给你发送“Activation Code”的,那是以 Individual 名义加入苹果开发者计划时才会收到的东东。

[转载]ASP.NET MVC 的统一异常处理有多难?

mikel阅读(1115)

[转载]ASP.NET MVC 的统一异常处理有多难? – 阿不 – 博客园.

一个比较顺手的开发框架,我们都希望开发人员不要去太关心异常的处理,除了一个特定异常需要特定处理外,我们都希望我们很多普通的异常都能由框架来 帮我们搞定。比如异常的日志记录,异常信息的提示,异常的进一步分类的判断等等,我们都不希望开发人员去使用相同或类似的代码去完成。简单来讲,我们不希 望我们的代码中出现太多的try…catch 代码。如果在一个项目中,频繁出现try…catch的代码块,一方面代码不太优雅,另一方面也会给我们的代码编码带来一定的障碍,由于变量作用域 (try和catch属于不同的代码块)的问题,我们很多时候不得不把变量定义在try…catch之外的代码块当中。因此,在很多业务逻辑的代码中,我 们一般都不太会去专门做异常的处理,而相反,我们经常会根据业务逻辑的需要抛出很多业务逻辑异常出来,抛给UI或是业务调用者,而这种异常很多时候是希望 显示给最终用户的友好信息提示。

因此,将异常的捕获,处理和显示放在UI代码中,无论从哪个角度来看都是最好的选择。结合ASP.NET MVC框架,为我们提供了的统一异常处理方案是重写Controller.OnException方法,或者是实现IExceptionFilter接口 的ActionFilter。然而,这样真的就可以满足我们统一异常处理的需要吗?来看看下面的几种情况:

1.

1 public ActionResult Index()
2 {
3 var model = GetModel();
4 return View(model);
5 }

在这种情况下,假设在GetModel的时候出现了异常,这时我们别无他法,即时你把异常捕获处理了,返回到Index View任何无法显示任何有用的信息。此时,我们重定向到统一友好错误页面是可以接受的。因此,在这种情况下,MVC提供的异常处理机制来统一处理这种情 况下的异常就会非常简单有效。

2.

01 [HttpPost]
02 public ActionResult Edit(User model)
03 {
04 if (ModelState.IsValid)
05 {
06 SaveModel(model);
07 return RedirectToAction("Index", "Home")
08 }
09
10 return View(model);
11 }

在这种情况下,假设我们在SaveModel时出现了异常,这个异常假设不是系统性异常,而是一个业务性异常。我们更希望是的,在用户当前操作页面 上提示该异常信息,保持用户输入值不变,用户只需要根据提示消息,修改一两个输入值即可再次提交表单,而不是重定向到错误提示页面之后再返回回来完全重新 输入表单。在这种要求下,MVC提供的异常处理机制就无法满足需要,因为model这种异常在统一的异常处理上下文中无法得到。因此,我们就只能添加异常 处理代码块了:

01 [HttpPost]
02 public ActionResult Edit(User model)
03 {
04 try
05 {
06 if (ModelState.IsValid)
07 {
08 SaveModel(model);
09 return RedirectToAction("Index", "Home")
10 }
11 }
12 catch (Exception e)
13 {
14 //log
15 ModelState.AddModelError("", e.Message);
16 }
17 return View(model);
18 }

而这样的代码,正是我们所希望避免的,然而这样的性质的Action在我们的系统中比比皆是。不过,此时在满足某种前提条件的情况下,假设我们的 Model变量名都是”model”,我们是有可能通过ActionExecutingContext.ActionParameters得到我们所要的 model值,提供给View。通过这种workaround的处理,我们也许可以很好的绕过此问题。我们再来看另一种情况:

3.

01 [HttpPost]
02 public ActionResult Edit(User user)
03 {
04 if (ModelState.IsValid)
05 {
06 SaveModel(user);
07 }
08 var model = GetModel(user.Name);
09 ViewData["Title"] = "Edit";
10 return View(model);
11 }

在这种情况下,也许我们除了try…catch外,真的没有其它更好的办法了。

异常处理一直都是我们软件开发过程当中,不得不去面对的麻烦。我们程序员都很害怕,因为一个个不可预期的异常而导致我们的业务模块无法正确运行,无 法友好的提示给用户而招来抱怨,但是我们又不喜欢因为这些可能并不经常发生的意外而多做很多零碎事情,而且会让代码变得很丑。在一般的业务系统当中,我们 更加不会加很多的catch并列句,去分门别类的处理各种各样的异常。如何更加简单,省事的把异常纳入可控的范围一直是我们努力的方向。

[转载]利用Attribute扩展MVC的Title和Sitemap

mikel阅读(1082)

[转载]利用Attribute扩展MVC的Title和Sitemap – Dozer .NET 技术博客 – 博客园.

开篇

无论是 ASP.NET 还是 MVC 中,想要设置网站的 Title 或者 Sitemap (不用控件)总是很麻烦。

Title 和 Sitemap 都是有关联的,所以有什么办法可以 Write once, run anywhere 呢?

先看一下效果和用法吧~

[效果]

image

[用法:Controller中]

image

[用法:View中]

image

[用法总结]

只要在 Controller 和 Action 上加上 Attribute 就可以设置当前 Controller 的 名字和 Action 的名字。

设置 Controller 和 Action 的属性

01 [NewPath("Demo", Controller = "Home", Action = "Index")]
02 public class HomeController : Controller
03 {
04 [NewPath("首页", Controller = "Home", Action = "Index")]
05 public ActionResult Index()
06 {
07 ViewData["Message"] = "欢迎使用 ASP.NET MVC!";
08 return View();
09 }
10
11 public ActionResult About()
12 {
13 this.SetNewPath("关于", new { Controller = "Home", Action = "About" });
14 return View();
15 }
16 }

这里,我这个网站名是Demo,那我给所有的 Controller 都加上 Demo 这个名称和相关信息即可

然后,有两张页面,分别是“首页”和“关于”

那我只要在 Action 上加上他们的名称和相关信息即可

Q1:是否可以加多个 Attrubute?

A1:可以,而且可以设置 Order 来设置他们的顺序

Q2:我需要,网站名、首页、文章、文章标题 这样的路径怎么办?

A2:代码如下,除了可以在 Attrubute 中设置外,还可以在 Action 代码中设置,因为有些信息需要经过处理后才能得到

01 [NewPath("Demo", Controller = "Home", Action = "Index", Order = 1)]
02 [NewPath("首页", Controller = "Home", Action = "Index", Order = 2)]
03 public class HomeController : Controller
04 {
05 [NewPath("新闻", Controller = "News", Action = "Index")]
06 public ActionResult Detail(int? id)
07 {
08 this.SetNewPath("新闻标题", new {Controller = "News", Action = "detail", id = id.Value});
09 return View();
10 }
11 }

在View中显示

1 一般把上图的代码放在 MasterPage 中,因为他们的用法都是调用同一个函数
1 除了上面提供的两个主要函数外,还有一个很自由的函数:
1 <h2><%=Html.GetSitemap() %></h2>
2 <h2><%=Html.GetWebPath("<a href=\"{1}\">{0}</a>", " / ") %></h2>

image

这里,只要传入显示模板和分隔符模板,就可以随意地自定义内容了

源代码和例子

下载地址

[转载]使用WCF 4.0 构建 REST Service

mikel阅读(1351)

[转载]使用WCF 4.0 构建 REST Service – Zhiming Jiang – 博客园.

用过一段时间的Ruby on Rails,感觉它内置的RESTful结构非常的完美,也对.NET WCF 3实现REST颇有微议,今天在.NET 4.0下试了新的WCF 4,发现其重写了对REST的支持,使用了类似MVC Routing来配置URL导向,非常迷人。

下面来看下如何一步一步来创建新的REST结构的WCF项目。

创建项目

1 打开VS 2010,选择新建项目,我们选择已有的模板来方便创建新的项目,在左侧Online Templates中选择WCF REST Service Template 40(CS)。

clip_image002

接下来去安装这个模板到本地,第一次安装时需要同意该使用协议,点击“安装”:

clip_image003

这样我们就很简单的用这个模板生成了一个新的项目。

改变之处

该模板使用了一种新的结构来创建简单的REST Service,在细读代码前,先看下项目的文件结构:

clip_image005

相对于之前的版本

l 项目中不再有SVC文件,这样就不能每次都通过xx.svc/users/1 来访问,而是通过URL Routing来配置。

l 也不再有接口文件作契约。

Global.asax配置

可以看到在.NET 4中构建REST服务相当容易。项目通过在Global.asax中来配置类似于ASP.NET 中的Routing进行URL重定向。见如下代码。

1 public class Global : HttpApplication
2 {
3 void Application_Start(object sender, EventArgs e)
4 {
5 RegisterRoutes();
6 }
7
8 private void RegisterRoutes()
9 {
10 // Edit the base address of Service1 by replacing the “Service1” string below
11 RouteTable.Routes.Add(new ServiceRoute(Service1, new WebServiceHostFactory(), typeof(Service1)));
12 }
13 }

通过代码我们可以看到,通过ServiceRoute类来进行URL重定向的,这里我们配置了一个名为Service1的Resource,指定到Service1类上。

Web.config

同时,在web.config中包含着部署所需要的一些配置。下面的代码是默认生成的。

1 <?xml version=”1.0″?>
2 <configuration>
3 <system.web>
4 <compilation Debug=”true” targetFramework=”4.0″ />
5 </system.web>
6
7 <system.webServer>
8 <modules runAllManagedModulesForAllRequests=”true”>
9 <add name=”UrlRoutingModule” type=”System.Web.Routing.UrlRoutingModule, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a” />
10 </modules>
11 </system.webServer>
12
13 <system.serviceModel>
14 <serviceHostingEnvironment aspNetCompatibilityEnabled=”true”/>
15 <standardEndpoints>
16 <webHttpEndpoint>
17 <!–
18 Configure the WCF REST service base address via the global.asax.cs file and the default endpoint
19 via the attributes on the <standardEndpoint> element below
20 –>
21 <standardEndpoint name=”” helpEnabled=”true” automaticFormatSelectionEnabled=”true”/>
22 </webHttpEndpoint>
23 </standardEndpoints>
24 </system.serviceModel>
25 </configuration>

Resource代码

默认生成的Resource:Service1代码,可以看到这是一个完整RESTful的结构,有着Get, Put, Post, Delete的完整支持。

1 [ServiceContract]
2 [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
3 [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
4 public class Service1
5 {
6 // GET /Service1/
7 [WebGet(UriTemplate = “”)]
8 public List<SampleItem> GetCollection()
9 {
10 return new List<SampleItem>() { new SampleItem() { Id = 1, StringValue = Hello } };
11 }
12
13 // POST /Service1/
14 [WebInvoke(UriTemplate = “”, Method = POST)]
15 public SampleItem Create(SampleItem instance)
16 {
17 throw new NotImplementedException();
18 }
19
20 // GET /Service1/100
21 [WebGet(UriTemplate = {id})]
22 public string Get(string id)
23 {
24 return welcome;
25 }
26
27 // PUT /Service1/100
28 [WebInvoke(UriTemplate = {id}, Method = PUT)]
29 public SampleItem Update(string id, SampleItem instance)
30 {
31 throw new NotImplementedException();
32 }
33
34 // DELETE /Service1/100
35 [WebInvoke(UriTemplate = {id}, Method = DELETE)]
36 public void Delete(string id)
37 {
38 // TODO: Remove the instance of SampleItem with the given id from the collection
39 throw new NotImplementedException();
40 }
41 }

运行测试

为了测试,将Get(string id)进行修改。可以直接运行项目(F5)。

在地址栏中加上Service1,可以看到打开一个空白页面,此时内容已经生成,只是XML数默认不直接显示在页面上。

clip_image007

通过查看其Source,可以看到返回的数据集。

clip_image008

此时参数为空,也就是会调用下面一个返回集合的方法:

1 [WebGet(UriTemplate = “”)]
2 public List<SampleItem> GetCollection()

同时,也可以发起带参数的GET请求,如/Service1/1/,则会调用相对应的参数函数:

1 [WebGet(UriTemplate = {id})]
2 public string Get(string id)

Help 页面

模板同时也为我们生成了一个帮助页面,帮助我们快速了解该Resource所对应的URI祥情。

clip_image010

clip_image012

布署到IIS 7

该项目的布署和普通ASP.NET项目相同,这里写下方法。

将项目发布到本地磁盘:

clip_image013

在IIS中新建一个Site,在右侧Action下有一个Add Web Site。也可以在Default Web Site下新建一个Application,方式相同:

clip_image015

这一步一定要选Application pool为 ASP.NET v4.0,端口任意指定,这里使用8080

clip_image016

再强调一次,一定要选ASP.NET v4.0

clip_image017

在浏览器中打开可以看到结果。

clip_image019

[转载]Comet技术选择论Is node.js best for Comet?

mikel阅读(969)

[转载]Comet技术选择,论Is node.js best for Comet? – Lua – 博客园.

http://sunxiunan.com/?p=1768

首先要声明,我对Comet技术只了解皮毛,下面的评论如果有错误欢迎各位看官指出。本文相关博客地址:http://amix.dk/blog/post/19577#Is-node-js-best-for-Comet amix在这篇博客中谈论他们在Plurk中Comet技术选择的变迁。

说句题外话,他有另外一篇博客 http://amix.dk/blog/post/19581#The-main-issue-with-non-blocking-servers
里面用两张图形象的介绍了阻塞式服务器与非阻塞式服务器的工作方式,感兴趣的可以去瞅瞅。amix关于node.js和v8的介绍可以看这里http://amix.dk/blog/post/19484#Comet-with-node-js-and-V8

关于Comet技术,可以参考维基百科 http://en.wikipedia.org/wiki/Comet_%28programming%29 国人有个开源项目http://code.google.com/p/eurasia/ 好像是做类似工作。

回到这篇博客上来,amix提到他们在项目中针对comet技术的选择,一开始是使用fast polling with C memcached nginx libevent,实现代码可以参考
http://amix.dk/blog/post/19414#Fast-polling-using-C-memcached-nginx-and-libevent 后来这个方案碰到局限了,不知什么局限,总之是不好用了。

于是实验了很多其它的comet方案,但是都不成熟。所以他们用Java与Netty实现一套comet方案,可以参考 http://amix.dk/blog/post/19456#Plurk-Comet-Handling-of-100-000-open-connections
文 章里提到Twisted缺点是太耗CPU而且不易扩展;Jetty太耗内存;Tomcat也是很耗费内存;apache Mina文档不行,而且也不易扩展。最后选择了Netty,amix没有提到他们如何用Netty实现的,所以估计想用这个方案的朋友得单独联系他了。

后来amix发现node.js不错,他把java方案移植到nodejs上,只用了2天时间。在过去8个月(从2010年2月到10月)nodejs方案每天可以服务几百万用户的comet提醒。

但是,总有但是,随着网站用户增多,nodejs方案也碰到瓶颈了。即使试着做了一些优化和增加硬件,效果并不明显。amix他们又回到Netty 方案,经过一些代码优化后,尽管内存使用量大于nodejs方案,但是性能要好于后者。Netty方案每秒可以为10000个客户端提供约6000个 comet提醒,而Nodejs方案只能每秒服务500个,所以可以说新的Netty方案有10倍以上改进。

amix总结道,node.js是一个非常棒的方案,至少撑了8个月,而且实现起来也很快。但是nodejs有致命的缺陷。这个缺陷来自nodejs的基石-V8 JavaScript引擎。V8引擎不支持线程或者进程机制-每件事都是主进程处理,甚至包括垃圾收集。

对于浏览器而已,这个限制是一个聪明的选择,大家知道每个Chrome页面就是一个单独的进程,所以V8引擎这种方案很好用。但是对于服务器架构就 不一样了,这种单进程单线程的限制就变得麻烦。(具体为何麻烦我也不知道,也没写过nodejs项目)关于V8在服务器端使用的局限性,Nginx作者也 有一篇博客介绍Why is Google V8 is not suitable for embedding in servers http://sysoev.ru/prog/v8.html 大家可以通过google翻译成英语阅读(翻译成中文后读起来很奇怪,还不如英语好懂),主要也是抱怨异常处理、进程模型、垃圾收集这几个方面。对于浏览器比较适合的V8方案,在服务器端就变成无法承受之重。

后面的回复也值得参考,其中有人提到使用nginx建立Nodejs集群然后分发,有人建议说重写nodejs的http模块很好用,也有人建议fugue这个方案http://github.com/pgte/fugue ,nodejs作者Ryan Dahl也留言说明前面版本某个bug可能导致性能问题。

偶个人的感想:即使amix有这样的抱怨,但可以看出nodejs依然是服务器端实现comet的很好选择,异步编程、高并发、低功耗,而且作者非 常活跃,社区膨胀的非常快,个人感觉nodejs活跃度已经超过Lua。Lua社区有些程序员也试图用libevent或者libev来为Lua加上非阻 塞异步服务器端编程的能量,但是影响力都不够,成熟度也不如nodejs。接下来偶会对nodejs做更多的探究,从源代码到小程序编写应用,希望能通过 nodejs提高一下自己对服务器端编程的理解。

[转载]C#也能PS图片还能为网站Ajax上传图片同时生成微缩图(附Demo)

mikel阅读(956)

[转载]C#也能PS图片,还能为网站Ajax上传图片同时生成微缩图(附Demo) – RyanDing – 博客园.

本文旨在与各位朋友们分享我是如何在项目中用C# “ps图片” 为网站生成同比例微缩图的解决方案。如有不足之处欢迎您指出。

一、技术概述


1.Ajax无刷新上传图片,详情请阅我的这篇文章。(JQuery + C# ashx)

2.C#位图处理  System.Drawing。

3.最新demo支持IE7,IE8,FireFox。

二、微缩图处理方法:


生成微缩图的核心方法:

CreateThumbnailPicture

/// <summary> /// 图片微缩图处理 /// </summary> /// <param name="srcPath">源图片</param> /// <param name="destPath">目标图片</param> /// <param name="width">宽度</param> /// <param name="height">高度</param> public static void CreateThumbnailPicture(string srcPath, string destPath, int width, int height) { //根据图片的磁盘绝对路径获取 源图片 的Image对象 System.Drawing.Image img = System.Drawing.Image.FromFile(srcPath); //bmp: 最终要建立的 微缩图 位图对象。 Bitmap bmp = new Bitmap(width, height); //g: 绘制 bmp Graphics 对象 Graphics g = Graphics.FromImage(bmp); g.Clear(Color.Transparent); //为Graphics g 对象 初始化必要参数,很容易理解。 g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality; g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High; g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality; //源图片宽和高 int imgWidth = img.Width; int imgHeight = img.Height; //绘制微缩图 g.DrawImage(img, new System.Drawing.Rectangle(0, 0, width, height), new System.Drawing.Rectangle(0, 0, imgWidth, imgHeight) , GraphicsUnit.Pixel); ImageFormat format = img.RawFormat; ImageCodecInfo info = ImageCodecInfo.GetImageEncoders().SingleOrDefault(i => i.FormatID == format.Guid); EncoderParameter param = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L); EncoderParameters parameters = new EncoderParameters(1); parameters.Param[0] = param; img.Dispose(); //保存已生成微缩图,这里将GIF格式转化成png格式。 if (format == ImageFormat.Gif) { destPath = destPath.ToLower().Replace(".gif", ".png"); bmp.Save(destPath, ImageFormat.Png); } else { if (info != null) { bmp.Save(destPath, info, parameters); } else { bmp.Save(destPath, format); } } img.Dispose(); g.Dispose(); bmp.Dispose(); }

部分代码已经加入注释,仔细阅读代码应该不难理解。下面介绍ashx中AJAX调用方法,我们在AJAX异步上传图片成功后对源图片进行”PS”。关键代码片段如下:

1 //上传成功后网站内源图片相对路径 2   string relativePath = System.Web.HttpContext.Current.Request.ApplicationPath 3 + string.Format(@"Content/Upload/Images/{0}", fileName); 4 5 /* 6 比例处理 7 微缩图高度(DefaultHeight属性值为 400) 8 */ 9 System.Drawing.Image img = System.Drawing.Image.FromFile(toFile); 10 int width = img.Width; 11 int height = img.Height; 12 float ratio = (float)width / height; 13 14 //微缩图高度和宽度 15   int newHeight = height <= DefaultHeight ? height : DefaultHeight; 16 int newWidth = height <= DefaultHeight ? width : Convert.ToInt32(DefaultHeight * ratio); 17 18 FileInfo generatedfile = new FileInfo(toFile); 19 string newFileName = "Thumb_" + generatedfile.Name; 20 string newFilePath = Path.Combine(generatedfile.DirectoryName, newFileName); 21 22 PictureHandler.CreateThumbnailPicture(toFile, newFilePath, newWidth, newHeight); 23 24 string thumbRelativePath = System.Web.HttpContext.Current.Request.ApplicationPath 25 + string.Format(@"/Content/Upload/Images/{0}", newFileName); 26 27 //返回原图和微缩图的网站相对路径 28   relativePath = string.Format("{0},{1}", relativePath, thumbRelativePath); 29 30 return relativePath;   

三、程序运行截图:


上传前:

上传后:


四、 小结:


我使用该方法主要是为了解决打印报表时由于图片大小没有合理的比例规范导致报表样式变形,同样该方法也适合网站或论坛由用户上传源图片生成微缩头像等。

如果您感兴趣可以在这里下载本例DEMO

最后希望本文能够帮助您解决开发中的类似问题。

[转载]Flex4 Net服务端内存数据管理

mikel阅读(1201)

[转载]Flex4 Net服务端内存数据管理 – 4K.Yu 刻录时光 – 博客园.

使用Flex+net开发程序,但还是停留在原来的web习惯上,想用session之类存储一个后台数据,但是,使用的不是webservice 方式,而且remoting方式,所以服务端没有session,那该怎么存储服务端的数据呢?当然是暂存,因为还没必要立刻插入到数据库中。

考 虑了好久,也google&baidu了好久,始终不得解。后来觉得是不是我的想法有问题,或许现在改用flex做前台,就不需要在服务器端暂存 数据了,我们已经把瘦客户端变成富客户端,同理,现在是瘦服务端,所以将中间数据暂存在客户端,然后服务端用的时候从客户端取呢?

后来考虑了,还是将数据存储在服务端,具体思路:

写一个单例Comm类来管理所有连接的数据,再用一个Vars类来具体管理每一个连接的数据。

Comm类部分代码:

代码

private volatile static Comm instance = null;
private static object lockHelper = new object();

private Comm()
{
SQLConn
= System.Configuration.ConfigurationManager.ConnectionStrings[brxConn].ConnectionString;
WebSite
= System.Configuration.ConfigurationManager.AppSettings[WebSite].ToString();
}
public static Comm Instance
{
get
{
if (instance == null)
{
lock (lockHelper)
{
if (instance == null)
{
instance
= new Comm();
}
}
}
return instance;
}
}
public static void ResetComm()
{
instance
= null;
}

然后在Comm中定义一个Hashtable ht来存储所有的Vars实例,各个连接用Guid来获取其对应的Vars:

代码

private Hashtable ht;//hashtable to store vars

public Vars getVarsbyGuid(string guid)
{
if (string.IsNullOrEmpty(guid))
return null;
if (ht == null)
ht
= new Hashtable();
//删除过期的vars,delete vars before 30 mins
Hashtable newHt = new Hashtable();
foreach (DictionaryEntry de in ht)
{
if (((Vars)de.Value).LastUpdate > DateTime.Now.AddMinutes(30))
{
newHt.Add(de.Key, de.Value);
}
}
ht
= newHt;
Vars myv
= null;
if (!ht.ContainsKey(guid))
{
myv
= new Vars();
myv.LastUpdate
= DateTime.Now;
ht.Add(guid, myv);
}
else
{
myv
= (Vars)ht[guid];
myv.LastUpdate
= DateTime.Now;
}
return (Vars)ht[guid];
}

同时为了节约内存,对超时的vars进行回收。

为了实现回收,需要在Vars中设置最后更新时间:

代码

public class Vars
{
/// <summary>
/// once lastupdate is 30minutes ago , we delete it from memory
/// </summary>
public DateTime LastUpdate { get; set; }

public DataSet dataSet { get; set; }
public string notes { get; set; }
public string report { get; set; }
public string textHead { get; set; }

public string regNo { get; set; }
public string companyName { get; set; }
public string finEnd { get; set; }
public string byType { get; set; }
public string byNet { get; set; }
public string bySingle { get; set; }
}

最后,总结下思路:

1服务器启动初始化Comm

2客户端连接,获取Guid

3利用Guid从Comm创建或获取Vars

4每次获取Vars时同步更新时间

5每次获取Vars时扫描全部Hashtable,将超时的Vars回收

6客户端退出时从Comm销毁Vars