[转载]利用WebBrowser彻底解决Web打印问题

mikel阅读(1050)

[转载]利用WebBrowser彻底解决Web打印问题 – 炭炭 – 博客园.
BS架构下的打印大家是怎么解决的呢,我最近作了一个项目正好负责这一块,不仅要求打印页面的特定部分,还要求有后台的批量打印,在网上查 了一些资料,最后终于解决了。抱着“取之于众 服务于众”的思想,我总结了一下,把它拿到网上来与大家分享,希望能帮助遇到类似问题的朋友。

我主要使用了IE内置的WebBrowser控件,无需用户下载和安装。WebBrowser有很多功能,除打印外的其他功能就不再赘述了,你所能用到的打印功能也几乎全部可以靠它完成,下面的问题就是如何使用它了。先说显示后打印,后面说后台打印。

1.首先引入一个WebBrowser在需要打印的页面,可以直接添加:

<object id=”WebBrowser” classid=CLSID:8856F961-340A-11D0-A96B-00C04FD705A2 height=”0″ width=”0″>
</object>

到页面,或者使用JavaScript在需要的时候临时添加也可以:

 

document.body.insertAdjacentHTML(“beforeEnd”,

 

    “<object id=\”WebBrowser\” width=0 height=0 \

 

classid=\”clsid:8856F961-340A-11D0-A96B-00C04FD705A2\”>”);

2 .页面设置和打印预览

如下所示,直接调用即可

 

 

document.all.WebBrowser.ExecWB(6,6)   直接打印
document.all.WebBrowser.ExecWB(8,1)   页面设置
document.all.WebBrowser.ExecWB(7,1)   打印预览

或者:

execScript(“document.all.WebBrowser.ExecWB 7, 1″,”VBScript”);

3 隐藏不打印的页面元素和分页

 

 CSS 有个Media 属性,可以分开设置打印和显示的格式。

 

如 <style media=”print” type=”text/css”> …</style> 中间的格式将只在打印时起作用,不会影响显示界面。
所以可以设定
<style media=”print” type=”text/css”>
.Noprint{display:none;}
.PageNext{page-break-after: always;}
</style>

然后给不想打印的页面元素添加: class=”Noprint” ,那就不会出现在打印和打印预览中了。
想分页的地方添加:  <div class=”PageNext”></div> 就可以了。

 

4.打印页面的特定部分

我是通过将需要打印的特定部分另建一个页面,然后装入主页面的一个IFrame中,再调用IFrame的打印方法,只打印IFrame中的内容实现的。
如:
<iframe style=”visibility: visible” name=”FrameId” width=”100%” height=”30%” src=”NeedPrintedPage.asp”></iframe>
下面的pringFrame  js函数将只打印Iframe中的内容,可以直接引用使用,如printFrame(FrameId);

window.print = printFrame;

 

// main stuff
function printFrame(frame, onfinish) {
if ( !frame ) frame = window;

 

  function execOnFinish() {
switch ( typeof(onfinish) ) {
case “string”: execScript(onfinish); break;
case “function”: onfinish();
}
if ( focused && !focused.disabled ) focused.focus();
}

 

  if (( frame.document.readyState !== “complete”) &&( !frame.document.confirm(“The document to print is not downloaded yet! Continue with printing?”) ))
{
execOnFinish();
return;
}

 

var eventScope = printGetEventScope(frame);
var focused = document.activeElement;

window.printHelper = function() {
execScript(“on error resume next: printWB.ExecWB 6, 1”, “VBScript”);
printFireEvent(frame, eventScope, “onafterprint”);
printWB.outerHTML = “”;
execOnFinish();
window.printHelper = null;
}

document.body.insertAdjacentHTML(“beforeEnd”,
“<object id=\”printWB\” width=0 height=0 \
classid=\”clsid:8856F961-340A-11D0-A96B-00C04FD705A2\”>”);

printFireEvent(frame, eventScope, “onbeforeprint”);
frame.focus();
window.printHelper = printHelper;
setTimeout(“window.printHelper()”, 0);
}

 

// helpers
function printIsNativeSupport() {
var agent = window.navigator.userAgent;
var i = agent.indexOf(“MSIE “)+5;
return parseInt(agent.substr(i)) >= 5 && agent.indexOf(“5.0b1”) < 0;
}

 

function printFireEvent(frame, obj, name) {
var handler = obj[name];
switch ( typeof(handler) ) {
case “string”: frame.execScript(handler); break;
case “function”: handler();
}
}

 

function printGetEventScope(frame) {
var frameset = frame.document.all.tags(“FRAMESET”);
if ( frameset.length ) return frameset[0];
return frame.document.body;
}

Iframe中所装载页面的打印效果在所装载页面设置就可以了,如分页等。

5.后台打印

我是通过建一个隐藏Iframe实现的,当然仍然会有页面装载的过程。
下面的函数创建Iframe装载页面并打印。如 printHidden(url)  //url为页面地址

function printHidden(url) {
document.body.insertAdjacentHTML(“beforeEnd”,
“<iframe name=printHiddenFrame width=0 height=0></iframe>”);
var doc = printHiddenFrame.document;
doc.open();
doc.write(“<body onload=\”parent.onprintHiddenFrame()\”>”);
doc.write(“<iframe name=printMe width=0 height=0 src=\”” +
url + “\”></iframe>”);
doc.write(“</body>”);
doc.close();
}

function onprintHiddenFrame() {
function onfinish() {
printHiddenFrame.outerHTML = “”;
if ( window.onprintcomplete ) window.onprintcomplete();
}
printFrame(printHiddenFrame.printMe, onfinish);
}

它用到了printFrame,所以别忘了引用前面的函数。

[转载]asp.net mvc的Routing、Controller、Filter学习笔记

mikel阅读(919)

[转载]asp.net mvc的Routing、Controller、Filter学习笔记 – wolfram – 博客园.

1、深入学习Routing

 

首先Routing的处于的位置,一个Http请求过来,Web容器接收到以后,将信息交给Routing(路由组件),Routing再进行处理~那么Routing的作用

 

确定Controller确定Action确定其他参数根据识别出来的数据, 将请求传递给Controller和Action.

 

小提示ASP.NET mvc预览版的时候,Routing组件还是作为ASP.NET mvc的一部分,后续的版本似乎就微软将其编译成一个独立的组件提供System.Web.Routing.dll,也就是说ASP.NET mvc项目是开源的,但是Routing组件并没有开源。Routing组件不仅在ASP.NET MVC中可以使用,也可以在WebForm中使用

 

首先我们新建一个ASP.NET MVC2/3的项目,新建好以后,直接运行为什么访问localhost/home/index会传递给 HomeController中名为index的action(即HomeController类中的index方法)?怎么实现的呢?

 

在我们新建的项目中,Global.asax文件中有以下方法

 


public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);

}

Routes是Application级别(全局)的,在Application开始的时候,程序注册路由,新建的项目默认只注册了一条路由,看下代码,

routes.MapRoute(
“Default”, // Route name
“{controller}/{action}/{id}”, // URL with parameters
new { controller = “Home”, action = “Index”, id = UrlParameter.Optional } // Parameter defaults
);

MapRoute第一个参数是此路由的名称,第二个参数是URL的参数形式,{controller}相当于是一个string.Format方法中的占位符,意思是这里可以是任意一个controller名称,

同理,action、id也是一样的,那为什么请求的/Home/Index并没有Id这个参数,第三个参数是路由规则默认值,这条路由默认的controller是home,action是index,而id呢,是可选的~~~当我们请求/Home/Index的时候,会被此路由获取,而我们直接请求http://localhost的时候,可以到Home/Index的时候,路由参数有默认值

Ok,到这里我们学习了如何注册路由,我们来试着自己写一条路由

routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

//自定义路由,
routes.MapRoute(
"myRoute", // Route name
"{controller}-{action}", // URL with parameters
new { controller = "Home", action = "Index" } // Parameter defaults
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);

然后重新启动程序,因为Routes是Application级别的,在我们修改Application级别信息后,应该退出,否则不会有效果滴,这个是好多初学者容易犯错的地方.如果是生产环境,应该重新启动下Web容器.

我们运行程序以后,请求域名/home-index一样可以请求页面,说明我们自定义的路由有效.

这里路由的规则非常灵活,我们可以自定义,以下的路由规则都可以

routes.MapRoute(
“myRoute”, // Route name
“{controller}-{action}-{1}-{2}-{3}”, // URL with parameters
new { controller = “Home”, action = “Index” } // Parameter defaults
);

 

MapRoute()方法

MapRoute有以下的重载方法

MapRoute( string name, string url);

MapRoute( string name, string url, object defaults);

MapRoute( string name, string url, string[] namespaces);

MapRoute( string name, string url, object defaults, object constraints);

MapRoute( string name, string url, object defaults, string[] namespaces);

MapRoute( string name, string url, object defaults, object constraints, string[] namespaces);

name参数: 规则名称, 可以随意起名.不可以重名,否则会发生错误: 路由集合中已经存在名为“Default”的路由。路由名必须是唯一的。

url参数: url获取数据的规则, 这里不是正则表达式,  将要识别的参数括起来即可, 比如: {controller}/{action} 最少只需要传递name和url参数就可以建立一条Routing(路由)规则.比如实例中的规则完全可以改为: routes.MapRoute( “Default”, “{controller}/{action}”);

defaults参数: url参数的默认值.如果一个url只有controller: localhost/home/ 而且我们只建立了一条url获取数据规则: {controller}/{action} 那么这时就会为action参数设置defaults参数中规定的默认值. defaults参数是Object类型,所以可以传递一个匿名类型来初始化默认值: new { controller = “Home”, action = “Index” } 实例中使用的是三个参数的MapRoute方法: routes.MapRoute( “Default”, // Route name “{controller}/{action}/{id}”, // URL with parameters new { controller = “Home”, action = “Index”, id = “” } // Parameter defaults );

constraints参数: 用来限定每个参数的规则或Http请求的类型.constraints属性是一个RouteValueDictionary对象,也就是一个字典表, 但是这个字典表的值可以有两种: 用于定义正则表达式的字符串。正则表达式不区分大小写。 一个用于实现 IRouteConstraint 接口且包含 Match 方法的对象。 通过使用正则表达式可以规定参数格式,比如controller参数只能为4位数字: new { controller = @”\d{4}”}

通过第IRouteConstraint 接口目前可以限制请求的类型.因为System.Web.Routing中提供了HttpMethodConstraint类, 这个类实现了IRouteConstraint 接口. 我们可以通过为RouteValueDictionary字典对象添加键为”httpMethod”, 值为一个HttpMethodConstraint对象来为路由规则添加HTTP 谓词的限制, 比如限制一条路由规则只能处理GET请求: httpMethod = new HttpMethodConstraint( “GET”, “POST” )

routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" }, // Parameter defaults
new { controller = @"\d{4}" , httpMethod = new HttpMethodConstraint( "GET", "POST" ) }
);

我们注册这样的一条路由

routes.MapRoute(
"test", // Route name
"{controller}-{action}-{id}", // URL with parameters
new { controller = "Home", action = "Index" }, // Parameter defaults
new { controller = @"^\w+", action = @"^\w+", id = @"^\d+" }
);

编译且运行,当我们请求/home-index-11可以请求到,而我们/home-index-1x这样的是不能匹配的,

那这样的规则的又有什么用处呢?在这里可以对请求进行过滤,比如我们的id只能是数字类型,防止一些非法检测

路由组件的调试

假设我们写了N条路由,当我们发送请求的时候,并没有被我们想要的规则所捕获解析,so..我们需要调试。

在我们的项目添加RouteDebug.dll的引用,并在Global.asax文件中的Application_Start方法添加以下代码

protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
//启动路由表调试
RouteDebug.RouteDebugger.RewriteRoutesForTesting(RouteTable.Routes);
}

编译后,我们启动程序,会发现有一个Route Tester页面,关于RouteDebug匹配的页面信息,请大家查询RouteDebug的手册.

Route Tester中的Route Data请求就是当前请求的路由信息

我们请求/home/index,从图中可以看到被第4条路由捕获到.

  那这样的路由有什么作用呢?我想大部分做SEO的朋友都有经验,二级页面和三级页面,爬虫抓取的频率显然是不一样的,这样我们可以将三级甚至更深层的页面构造成二级页面~这个也是SEO的技巧之一

注意:我们在写路由规则的时候,因为路由规则有前后顺序(指注册的先后顺序),也许写的路由规则被它前面的规则给捕获到,进行处理。那后面注册的路由就无效

 

2、Controller学习

ASP.NET MVC中, 一个Controller可以包含多个Action. 每一个Action都是一个方法, 返回一个ActionResult实例.

ActionResult类包括ExecuteResult方法, 当ActionResult对象返回后会执行此方法.

Controller 处理流程:

1. 页面处理流程 发送请求 –> UrlRoutingModule捕获请求 –> MvcRouteHandler.GetHttpHandler() –> MvcHandler.ProcessRequest

2.MvcHandler.ProcessRequest() 处理流程: 使用工厂方法获取具体的Controller –> Controller.Execute() –> 释放Controller对象

3.Controller.Execute() 处理流程: 获取Action –> 调用Action方法获取返回的ActionResult –> 调用ActionResult.ExecuteResult() 方法

4.ActionResult.ExecuteResult() 处理流程: 获取IView对象-> 根据IView对象中的页面路径获取Page类-> 调用IView.RenderView() 方法(内部调用Page.RenderView方法)

Controller对象的职责是传递数据,获取View对象(实现了IView接口的类),通知View对象显示.

View对象的作用是显示.虽然显示的方法RenderView()是由Controller调用的,但是Controller仅仅是一个”指挥官”的作用, 具体的显示逻辑仍然在View对象中.

注意IView接口与具体的ViewPage之间的联系.在Controller和View之间还存在着IView对象.对于ASP.NET程序提供了 WebFormView对象实现了IView接口.WebFormView负责根据虚拟目录获取具体的Page类,然后调用 Page.RenderView()

 

Controller中的ActionResult

在Controller中,每一个Aciton返回都是ActionResult,我们通过查看ActionResult的定义

// Summary:
// Encapsulates the result of an action method and is used to perform a framework-level
// operation on behalf of the action method.
public abstract class ActionResult
{
// Summary:
// Initializes a new instance of the System.Web.Mvc.ActionResult class.
protected ActionResult();

// Summary:
// Enables processing of the result of an action method by a custom type that
// inherits from the System.Web.Mvc.ActionResult class.
//
// Parameters:
// context:
// The context in which the result is executed. The context information includes
// the controller, HTTP content, request context, and route data.
public abstract void ExecuteResult(ControllerContext context);
}

关于ActionResult的派生类,大家可以参考:http://blog.csdn.net/steven_husm/article/details/4641281

 

3、Filter的学习

mvc项目中,action在执行前或执行后想做一些特殊的操作,比如身份校验、行为截取等,asp.net mvc提供了以下几种默认的Filter

ASP.NET MVC 框架支持以下几种筛选器:

1、授权筛选器– 实现了 IAuthorizationFilter 接口

这一类的筛选器用来实现用户验证和对Action的访问授权。比如Authorize 就属于Authorization 筛选器。

2、Action 筛选器– 实现了 IActionFilter 接口

它可以包含一些Action执行前或者执行后的逻辑,比如有一些筛选器专门用来修改Action返回的数据。

3、Result 筛选器– 实现了 IResultFilter 接口

它可以包含一些view result生成前或者生成后的逻辑,比如有一些筛选器专门用来修改视图向浏览器展现前的结果。

4、异常筛选器– 实现了IExceptionFilter 接口

它用以用来处理Action或者Result的错误,也可以记录错误。

筛选器的默认执行顺序也和上面的列出的序号相同,比如Authorization 筛选器会先于Action 筛选器执行,而Exception 筛选器总会在最后执行。当然你也可以根据需要通过Order属性设定筛选器执行的顺序。

下面通过一个实际的例子来说明应用,新建一个mvc3项目,在项目中新加一个Common文件夹,并新加一个类LogUserOperationAttribute.cs

public class LogUserOperationAttribute : ActionFilterAttribute
{
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
//todo写日志代码,这里注意并发性
File.AppendAllText(@"C:\log.txt", string.Format("{0}日志", DateTime.Now));
base.OnResultExecuted(filterContext);
}
}

新加一个HomeControllers,并在HomeControllers中新加一个Action–Index以及视图文件

public class HomeController : Controller
{
//
// GET: /Home/
[LogUserOperation]
public ActionResult Index()
{
return View();
}
}

然后保存代码,F5运行,当页面显示出来以后,在C盘已经有log.txt文件.

abstract class ActionFilterAttribute这四个方法分别代表,Action执行时,Action执行后,Result返回时,Result返回后。(它们的执行顺序跟下图一致)

当然,我们也可以在ASP.NET MVC 3.0中增加Global Action Filter,这个就把此类filter变成全局的filter,所有Controller的action都会通过个filter的规则来执行,它跟我们在Controller或某个action所标识的属性有很大的区别,就是全局跟部分的区别。对于Global Action Filter 有着很多的应用,比如系统的权限、系统异常的处理

Gloable Filter实际应用–系统异常处理体系

我们程序运行过程中会有各种不可预料的情况,执行某个Action会发生异常,那我们异常信息需要记录下来,我们可以像上面的例子一样,在Action或Controller上打上标记,但是那么多action和Controller都去打标记,确实是很痛苦的事情,而asp.net mvc3有一个全局的Filter,我们只需要将我们自定义的Filter注册成全局的Filter

在Common文件夹中,新建一个类CustomHandleErrorAttribute.cs

public class CustomHandleErrorAttribute : IExceptionFilter
{
public void OnException(ExceptionContext filterContext)
{
File.AppendAllText(@"C:\error.txt", string.Format("{0}错误{1}", DateTime.Now, filterContext.Exception.Message));
}
}

在Global.asax文件中,RegisterGlobalFilters方法写注册代码

public class HomeController : Controller
{
//
// GET: /Home/
[LogUserOperation]
public ActionResult Index()
{
return View();
}
public ActionResult Error()
{
try
{
System.IO.File.Open("C:\\111111.exe", System.IO.FileMode.Open);
}
catch (Exception ex)
{
throw ex;
}
return View();
}
}

编译后运行项目~我们请求/Home/Error这个action,,程序出现异常,我们切换到C盘,发现C盘已经有error.txt文件
注册到全局的Filters所有的ActionResult执行前后都会调用我们的CustomHandleErrorAttribute的重写的方法。

GlobalFilters、ControllerFilters、ActionFilters的执行顺序问题

GlobalFilters–>ControllerFilters–>ActionFilters《这个是有执行的前置条件的》

当然这是在CustomHandleErrorAttribute类的定义上打上标记[AttributeUsage(AttributeTargets.All, AllowMultiple = true)]的前提下。不然 如果Action打上了标签跟Controller的相同则它只会执行Action上的Filter

[转载]51地图API离线包下载

mikel阅读(1221)

[转载]51地图API离线包下载 – gisvip – 博客园.

最近都在各种离线包,
也提供个51地图的离线包,供大家学习研究.

51地图吸取了Google Maps、Yahoo Maps 和国内同行的优点,
由原来的使用经纬度直投,瓦片大小200*200
转为Web墨卡托,瓦片大小256*256

不过51地图瓦片数据源的编码规则还是很不一样的.值得研究哈
51地图的图片存放规则是从左下开始编号,即左下角为0,0开始

目前官方的api存在bug,
http://api.51ditu.com/docs/mapsapi/examples/LTMaps/handleMouseScroll_at_center_mapcartoon.htm
就是如果使用了鼠标中键的动画的话,
在点鱼骨架上的向东,南,北,西 会提示错误.
同样这个离线包也存在这个bug
用法: 在iis中主目录指向51map

ie中输入
http://127.0.0.1/index.htm
就可以访问了哈


从51地图API迁移到MapABC地图API
http://wenku.baidu.com/view/9bb3e47202768e9951e738ba.html

离线包下载http://files.cnblogs.com/gisvip/51map.rar

请勿商用,只供大家学习交流.51地图还是很不错的.支持国产

商用请联系灵图公司,产生一起问题后果自负

更多交流 请到GISVIP社区交流

http://bbs.gisvip.com

[转载]ASP.NET MVC Model元数据及其定制一个重要的接口IMetadataAware

mikel阅读(910)

[转载]ASP.NET MVC Model元数据及其定制:一个重要的接口IMetadataAware – Artech – 博客园.

在介绍用于自定义Model元数据属性的AdditionalMetadataAttribute特性时我们提到了它实现的接口 IMedataAware,我们说这是一个非常重要并且有用的接口,通过自定义实现该接口的特性我们可以对最终生成的Model元数据进行自由地定制。如 下面的代码片断所示,IMedataAware接口具有唯一的方法成员OnMetadataCreated。当Model元数据被创建出来后,会先获取上 述的这一系列标注特性对其进行初始化,然后获取应用在目标元素上所有实现了IMedataAware接口的特性,并将初始化的ModelMetadata 对象作为参数调用OnMetadataCreated方法。所以我们通过创建实现该接口的特性不仅仅可以添加一些额外的元数据属性,也可以修改已经通过相 应的标注特性初始化的相关属性。[本文已经同步到《How ASP.NET MVC Works?》中]

1: public interface IMetadataAware

2: {

3: void OnMetadataCreated(ModelMetadata metadata);

4: }

ASP.NET MVC定义了两个实现了IMedataAware接口的特性,一个就是我们已经介绍过的AdditionalMetadataAttribute,另一个则是AllowHtmlAttribute。
一、AllowHtmlAttribute

为了防止最终用于通过在针对某个数据的输入中注入一些HTML来攻击我们的Web应用,ASP.NET MVC在进行Model绑定之前会对对应的请求数据进行验证,确保没有任何HTML标记包含其中。这个针对HTML标记的验证通过ModelMetadata的RequestValidationEnabled来控制,如下面的代码片断所示,这是一个布尔类型的可读写属性。该属性在默认情况下为True,意味着默认开启针对HTML标记的请求验证。

1: public class ModelMetadata

2: {

3: //其他成员

4: public virtual bool RequestValidationEnabled { get; set; }

5: }

AllowHtmlAttribute特性,顾名思义,就是运行作为目标元素的内容包含HTML标记。如下面的代码片断所示,AllowHtmlAttribute是实现了IMetadataAware 接口,在OnMetadataCreated方法中它直接将作为参数的ModelMetadata对象的RequestValidationEnabled属性设置为False,从而使针对目标对象的请求验证被忽略掉。

1: [AttributeUsage(AttributeTargets.Property, AllowMultiple=false, Inherited=true)]

2: public sealed class AllowHtmlAttribute : Attribute, IMetadataAware

3: {

4: public void OnMetadataCreated(ModelMetadata metadata)

5: {

6: //其他操作

7: metadata.RequestValidationEnabled = false;

8: }

9: }

为了验证ASP.NET MVC针对HTML标记的请求验证和AllowHtmlAttribute的作用,我们来做一个简单的实例演示。在通过Visual Studio提供的ASP.NET MVC项目模板创建的空Web应用中,我们定义了如下一个数据类型Foo,其中属性Baz上应用了AllowHtmlAttribute特性。

1: public class Foo

2: {

3: public string Bar { get; set; }

4:

5: [AllowHtml]

6: public string Baz { get; set; }

7: }

然后我们创建如下一个默认的HomeController,默认的Index操作方法中具有一个类型为Foo的参数,该参数直接作为Model呈现在默认的View中。

1: public class HomeController : Controller

2: {

3: public ActionResult Index(Foo foo)

4: {

5: return View(foo);

6: }

7: }

如下所示的Index操作对应的View定义,这是一个以Foo为Model的强类型View。在该View中,我们直接调用HtmlHelper的EditorForModel方法将Foo对象以编辑模式呈现出来。

1: @model Foo

2: @{

3: ViewBag.Title = "Index";

4: }

5: @Html.EditorForModel()

现在我们直接运行该Web应用。根据Model绑定的规则我们知道,如果我们通过浏览器访问HomeController的Index操作,可以通 过查询字符串的方式对该操作方法的参数进行初始化。具体来说,我们可以分别指定名称为Bar和Baz的查询字符串对作为参数的Foo对象的两个属性进行初 始化。为了验证对包含HTML标记的输入的验证,我们将最终绑定到Model上的查询字符串设置为<script/>。

如下图所示,由于Foo的属性Baz上应用了AllowHtmlAttribute特性是之支持包含HTML标记的数据,所以我们以查询字符串方式指定的包含HTML标记的内容(<script/>)直接显示在相应的文本框中。但是Bar属性在默认情况下是不运行绑定的数据具有任何HTML标记的,所以会将输入的数据视为恶意注入的HTML,直接抛出异常。

image

二、实例演示:创建实现IMetadataAware接口的特性定制Model元数据

通过上面对Model元数据定义的介绍我们知道显示名称可以通过在数据类型或者属性成员上应用DisplayAttribute特性来定义。在使用 该特性的时候,我们需要显式制定表示显示名称的Name属性,如果需要进行本地化处理,需要将显示内容定义在某个资源文件中,并通过 ResourceType属性指定该资源文件生成的类型。[源代码从这里下载]

为了简化,我们通过实现IMetadataAware接口的方式定义了如下一个DisplayTextAttribute特性。该特性的属性 DisplayName/ResourceType与DisplayAttribute的Name/ResourceType具有相同的作用,唯一不同的 是DisplayTextAttribute的这两个属性均是可以缺省的。如果DisplayName没有显式指定,则默认使用属性名称或者类型名称;如 果ResourceType没有显式指定,则采用通过静态字段staticResourceType表示的默认资源类型,该类型通过静态方法 SetResourceType进行注册。

1: [AttributeUsage(AttributeTargets.Class| AttributeTargets.Property)]

2: public class DisplayTextAttribute: Attribute, IMetadataAware

3: {

4: private static Type staticResourceType;

5: public string DisplayName { get; set; }

6: public Type ResourceType { get; set; }

7:

8: public DisplayTextAttribute()

9: {

10: this.ResourceType = staticResourceType;

11: }

12:

13: public void OnMetadataCreated(ModelMetadata metadata)

14: {

15: this.DisplayName = this.DisplayName ?? (metadata.PropertyName ?? metadata.ModelType.Name);

16: if (null == this.ResourceType)

17: {

18: metadata.DisplayName = this.DisplayName;

19: return;

20: }

21: PropertyInfo property = this.ResourceType.GetProperty(this.DisplayName, BindingFlags.NonPublic|BindingFlags.Public| BindingFlags.Static);

22: metadata.DisplayName = property.GetValue(null, null).ToString();

23: }

24:

25: public static void SetResourceType(Type resourceType)

26: {

27: staticResourceType = resourceType;

28: }

29: }

DisplayTextAttribute对Model元数据的定制实现在OnMetadataCreated方法中。具体来说,我们根据设置的DisplayName和ResourceType属性解析出最终作为目标元素显示名称的文本作为ModelMetadata的DisplayName属性值。

接下来我们来演示如何使用这个DisplayTextAttribute特性来替换DisplayAttribute特性进行显示名称的设置,为此我们在通过Visual Studio的ASP.NET MVC 项目模板创建的空Web应用中创建如下一个表示员工的Employee类型。Employee所有的属性上均应用了DisplayTextAttribute特性,而DisplayName和ReourceType属性没有显式指定。

1: public class Employee

2: {

3: [DisplayText]

4: public string Name { get; set; }

5:

6: [DisplayText]

7: public string Gender { get; set; }

8:

9: [DisplayText]

10: [DataType(DataType.Date)]

11: public DateTime BirthDate { get; set; }

12:

13: [DisplayText]

14: public string Department { get; set; }

15: }

接下来我们打开项目的属性对话框并选择“资源(Rources)”Tab页,按照如下图所示为Employee中的四个属性定义相应的资源字符串作为显示的名称,资源字符串条目的名称为属性名。

image

该资源文件会自动生成一个类型为Resources的内部类型。由于应用在Employee属性上的DisplayTextAttribute特性 并没有显式指定资源类型,所以我们需要在Global.asax文件中通过如下的方式将Resources类型注册为默认的资源类型。

1: public class MvcApplication : System.Web.HttpApplication

2: {

3: //其他成员

4: protected void Application_Start()

5: {

6: //其他操作

7: DisplayTextAttribute.SetResourceType(typeof(Resources));

8: }

9: }

现在我们通过调用HtmlHelper<TModel>的EditorForModel方法将一个具体的Employee对象以编辑模 式显示在某个Model类型为Employee的强类型View上,会呈现出如图4-6所示的效果,我们可以看到作为标签显示的文字正式我们定义在资源文 件中的内容。

image

ASP.NET MVC Model元数据及其定制: 初识Model元数据
ASP.NET MVC Model元数据及其定制: Model元数据的定制
ASP.NET MVC Model元数据及其定制:一个重要的接口IMetadataAware

[转载]Android分享到腾讯微博,信息,新浪微博等等的实现方式 - 天威茫然 - 博客园

mikel阅读(1130)

[转载]Android分享到腾讯微博,信息,新浪微博等等,的实现方式 – 天威茫然 – 博客园.

效果图:

 

 

 

 

 

XML:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/hello" />

    <Button
        android:id="@+id/btnFenXiang"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="分享" />

</LinearLayout>

java:

package hzl.pak.UI;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class FenxiangActivity extends Activity {
    private Button btnFenXiang = null;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        btnFenXiang = (Button) findViewById(R.id.btnFenXiang);
        btnFenXiang.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                Intent intent = new Intent(Intent.ACTION_SEND); //启动分享发送的属性
                intent.setType("text/plain");                                    //分享发送的数据类型
                intent.putExtra(Intent.EXTRA_SUBJECT, "subject");    //分享的主题
                intent.putExtra(Intent.EXTRA_TEXT, "extratext");    //分享的内容
                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//这个也许是分享列表的背景吧
                FenxiangActivity.this.startActivity(Intent.createChooser(intent, "分享"));//目标应用选择对话框的标题
            }
        });
    }

}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="hzl.pak.UI"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk android:minSdkVersion="8" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity
            android:name=".FenxiangActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
            <intent-filter android:label="@string/albums_sendbyWBlog">
                <action android:name="android.intent.action.SEND" />
                <data android:mimeType="image/*" />                
         <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
                
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest><?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="hzl.pak.UI"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk android:minSdkVersion="8" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity
            android:name=".FenxiangActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
            <intent-filter android:label="@string/albums_sendbyWBlog">
                <action android:name="android.intent.action.SEND" />
                <data android:mimeType="image/*" />                
         <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
                
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

注意配置文件里面的:




         

据说没这个腾讯微薄的不会出来,这个是网上别人反编译过的代码。

[转载]SQL Server 2005/2008/2012中应用分布式分区视图

mikel阅读(871)

[转载]SQL Server 2005/2008/2012中应用分布式分区视图 – 邀月 – 博客园.

自2000版本起,SQL Server企业版中引入分布式分区视图,允许你为分布在不同的SQL 实例的两个或多个水平分区表创建视图。

简要步骤如下:根据Check约束中定义的一组值把大表分割成更小的一些表。Check约束确保每个小表保存着不能保存在其他表的唯一数据。然后使用Union All创建分布式分区视图,把所有这些小表联结成单独的结果集。

这样对性能的改善是有益的,例如,如果视图根据日期分区,并用查询来返回仅保存在一个分区表中的行,那么SQL Server会智能地只搜索一个分区而不是分布式分区视图中的所有表。

我们假设一个场景,某公司成立上海和北京分公司,分别有各自的SQL Server实例来保存网站数据,都希望用一个表跟踪网站点击。点击量非常大。此时,需要一个视图以在单个视图中引用各自的表。公司希望能查询任意一个服 务器,并且返回相同的数据或各自分公司的数据。

下面我们通过实例来演示这个场景的具体应用。假定有两个实例:AP4\NET2012和AP4\NET2013(本文所有示例均在SQL Server 2008环境下通过)。

一、创建链接服务器,当然也可以通过OpenRowset(http://msdn.microsoft.com/zh-cn/library/ms190312.aspx)而不创建链接服务器,并创建测试数据库和表。

/********* 创建一个分布式分区视图 ***************/
/********* 3w@live.cn 邀月 ***************/

USE master GO
EXEC sp_addlinkedserver 'AP4\NET2013', N'SQL Server'
GO

-- 跳过远程实例架构表的检查,以提升性能,邀月注
EXEC sp_serveroption 'AP4\NET2013', 'lazy schema validation', 'true'
GO

--创建测试数据库
IF NOT EXISTS (SELECT name FROM sys.databases WHERE name = 'RemoteViewTest2012') BEGIN
CREATE DATABASE RemoteViewTest2012 END
GO
--打开测试库
Use RemoteViewTest2012 GO

--创建上海分公司的点击表
CREATE TABLE dbo.WebHits_ShangHai (WebHitID uniqueidentifier NOT NULL, WebSite varchar(20) NOT NULL , HitDT datetime NOT NULL, CHECK (WebSite = 'ShangHai'), CONSTRAINT PK_WebHits PRIMARY KEY (WebHitID, WebSite))

 

 

第二个实例:

/*************** 实例 AP4\NET2013(SQL Server 2008) *********/
/********* 3w@live.cn 邀月 ***************/
USE master GO
EXEC sp_addlinkedserver 'AP4\NET2012', N'SQL Server'
GO

-- 跳过远程实例架构表的检查,以提升性能,邀月注
EXEC sp_serveroption 'AP4\NET2012', 'lazy schema validation', 'true'
GO

IF NOT EXISTS (SELECT name FROM sys.databases WHERE name = 'RemoteViewTest2012') BEGIN
CREATE DATABASE RemoteViewTest2012 END
GO

--打开测试库
Use RemoteViewTest2012 GO

--创建北京分公司的点击表
CREATE TABLE dbo.WebHits_BeiJing (WebHitID uniqueidentifier NOT NULL, WebSite varchar(20) NOT NULL , HitDT datetime NOT NULL, CHECK (WebSite = 'BeiJing'), CONSTRAINT PK_WebHits PRIMARY KEY (WebHitID, WebSite))

 

二、在两个实例中分别创建视图

/*************** 实例 AP4\NET2012(SQL Server 2008) *********/
/********* 3w@live.cn 邀月 ***************/

--打开测试库
Use RemoteViewTest2012 GO

--创建分区视图
CREATE VIEW dbo.v_WebHits AS
SELECT WebHitID, WebSite, HitDT FROM RemoteViewTest2012.dbo.WebHits_ShangHai UNION ALL
SELECT WebHitID, WebSite, HitDT FROM [AP4\NET2013].RemoteViewTest2012.dbo.WebHits_BeiJing GO

/*************** 实例 AP4\NET2013(SQL Server 2008) *********/
/********* 3w@live.cn 邀月 ***************/

--打开测试库
Use RemoteViewTest2012 GO

--创建分区视图
CREATE VIEW dbo.v_WebHits AS
SELECT WebHitID, WebSite, HitDT FROM RemoteViewTest2012.dbo.WebHits_BeiJing UNION ALL
SELECT WebHitID, WebSite, HitDT FROM [AP4\NET2012].RemoteViewTest2012.dbo.WebHits_ShangHai GO

 

三、插入测试数据

我们可以选择任意一个实例中插入,下面我们选择AP4\NET2013

/*************** 实例 AP4\NET2013(SQL Server 2008) *********/
/********* 3w@live.cn 邀月 ***************/
----要保证插入,必须打开XACT_ABORT开关,并开启分布式事务协调器,邀月注

--打开测试库
Use RemoteViewTest2012 GO

SET XACT_ABORT ON
INSERT dbo.v_WebHits (WebHitID, WebSite, HitDT) VALUES(NEWID(), 'ShangHai', GETDATE()) INSERT dbo.v_WebHits (WebHitID, WebSite, HitDT) VALUES(NEWID(), 'BeiJing', GETDATE())

 

注意,如果该实例所在的服务器上没有启用MSDTC(Microsoft 分布式事务处理协调器),会抛出一个错误:

邀月工作室

此时在命令行中输入Net start msdtc以启用该服务。

邀月工作室

邀月工作室

如果还是不能正常启动MSDTC,请查阅MSDN(http://msdn.microsoft.com/zh-cn/library/aa561924%28BTS.10%29.aspx)以获取帮助。

 

四、进行分布式查询

此时,我们在任意一个实例查询的结果都是一致的,也正是我们想要的。

/*************** 实例 AP4\NET2013(SQL Server 2008) *********/
/********* 3w@live.cn 邀月 ***************/
/***** 分布式查询  **************/

----AP4\NET2013上查询 --打开测试库
Use RemoteViewTest2012 GO
SET XACT_ABORT ON

SELECT WebHitID, WebSite, HitDT FROM dbo.v_WebHits SELECT WebHitID, WebSite, HitDT FROM [AP4\NET2012].RemoteViewTest2012.dbo.WebHits_ShangHai

----AP4\N ET2012上查询 --打开测试库
Use RemoteViewTest2012 GO

SET XACT_ABORT ON

SELECT WebHitID, WebSite, HitDT FROM dbo.v_WebHits SELECT WebHitID, WebSite, HitDT FROM [AP4\NET2013].RemoteViewTest2012.dbo.WebHits_BeiJing

 

邀月工作室

我们欣喜地看到,SQL Server并没有在基础分区表中插入冗余数据,而是自动分发到了Check所约定的相应的表中,这得益于MSDTC的功劳。

邀月工作室

注意:创建分布式视图的注意事项和必要条件,请看MSDN(http://msdn.microsoft.com/zh-cn/library/ms188299.aspx)。

 

小结:分布式分区视图允许我们跨多个SQL Server实例划分数据。对于超大型数据库和拥有大量事务和读操作的SQL Server实例来说,这种设计让我们获益良多。根据被查询的视图,SQL Server能确定只查询本地分区表是否能满足某个查询请求,远程表是否需要查询,最终,SQL Server会最大限度地减少SQL Server实例间传输的数据总量。

邀月注:本文版权由邀月和博客园共同所有,转载请注明出处。
助人等于自助!  3w@live.cn

[转载]ASP.NET MVC Model元数据及其定制 [上篇]

mikel阅读(954)

[转载]ASP.NET MVC Model元数据及其定制 [上篇] – Artech – 博客园.

Contronoller激活之后,ASP.NET MVC会根据当前请求上下文得到目标Action的名称,然后解析出对应的方法并执行之。在整个Action方法的执行过程中,Model元数据的解析是 一个非常重要的环节。ASP.NET MVC中的Model实际上View Model,表示最终绑定到View上的数据,而Model元数据描述了Model的数据结构,以及Model的每个数据成员的一些特性。正是有了 Model元数据的存在,才使模板化HTML的呈现机制成为可能。此外,Model元数据支撑了ASP.NET MVC的Model验证体系,因为针对Model的验证规则正是定义在Model元数据中。ASP.NET MVC的Model元数据通过类型ModelMetadata表示。ModelMetadata通过一系列的属性描述了Model及其成员相关的元数据信息,在正式介绍这些元数据选项之前,我们很有必要先来了解一下Model元数据层次化结构。[本文已经同步到《How ASP.NET MVC Works?》中]

目录
一、Model元数据层次化结构
二、基本Model元数据信息
三、Model元数据的定制
UIHintAttribute
HiddenInputAttribute与ScaffoldColumnAttribute
DataTypeAttribute与DisplayFormatAttribute
EditableAttribute与ReadOnlyAttribute
DisplayAttribute与DisplayNameAttribute
RequiredAttribute
四、IMetadataAware接口
AllowHtmlAttribute
实例演示:创建实现IMetadataAware接口的特性定制Model元数据

一、Model元数据层次化结构

作 为Model的数据类型可以一个和简单的字符串或者是一个值类型的对象,也可能是一个复杂的数据类型。对于一个复杂的数据类型,基于类型本身和数据成员的 元数据都通过一个ModelMetadata来表示,而某个数据成员又可能是一个复杂类型,所以通过ModelMetadata对象表示的Model元数 据实际上具有一个树形层次化结构。

举个例子,我们具有一个具有如下定义的表示联系人的数据类型Contact。属性Name、 PhoneNo、EmailAddress和Address分别代表姓名、电话号码、邮箱地址和联系地址。联系地址通过另一个数据类型Address表 示,属性Province、City、District和Street分别表示所在省份、城市、城区和街道。

1: public class Contact

2: {

3: public string Name { get; set; }

4: public string PhoneNo { get; set; }

5: public string EmailAddress { get; set; }

6: public Address Address { get; set; }

7: }

8: public class Address

9: {

10: public string Province { get; set; }

11: public string City { get; set; }

12: public string District { get; set; }

13: public string Street { get; set; }

14: }

如果将Contact类型作为Model,作为其元数据的ModelMetadata不仅仅具有Contact类型本身和其属性成员的描述,由于其 Address属性是一个复杂类型,元数据还需要描述定义在该类型中的4个属性成员。下图反映基于Contact类型的Model元数据的层次化结构。

image

表示Model元数据的ModelMetadata类型不仅用于描述某个作为Model的数据类型,还用于递归地描述其所有属性成员(不包含字段成员),所以ModelMetadata具有一个树型层次化结构,这也可以从ModelMetadata的定义可以看出来。

1: public class ModelMetadata

2: {

3: //其他成员

4: public virtual IEnumerableProperties { get; }

5: }

如上面的代码片断所示,ModelMetadata具有一个类型为IEnumerable<ModelMetadata>的只读属性 Properties,表示用于描述属性/字段成员的ModelMetadata集合。ModelMetadata的层次化结构可以通过如下图所示的 UML来体现。由于基于类型的ModelMetadata和基于数据成员的ModelMetadata是一种包含关系,我们可以将前者称为后者的容器 (Container)。

image

二、基本Model元数据信息

基于作为Model类型创建的元数据主要是为View实现模板化HTML呈现和数据验证服务的,我们可以通过在类型和数据成员上应用相应的特性控制 Model在View中的呈现方式或者定义相应的验证规则。在介绍声明式Model元数据编程方式之前,我们先来介绍表示Model元数据的 ModelMetadata类型中与UI呈现和数据验证无关的基本属性。

1: public class ModelMetadata

2: {

3: //其他成员

4: public Type ModelType { get; }

5: public virtual bool IsComplexType { get; }

6: public bool IsNullableValueType { get; }

7: public Type ContainerType { get; }

8:

9: public object Model { get; set; }

10: public string PropertyName { get; }

11:

12: public virtual DictionaryAdditionalValues { get; }

13: protected ModelMetadataProvider Provider { get; set; }

14: }

如上面的代码片断所示,ModelMetadata具有四个类型相关的只读属性。ModelType表示Model本身的类型,比如说针对上面定义的Contact类型的ModelMetadata对象,其ModelType属性值就是Contact类型;而针对其属性的ModelMetadata对象,则具体的属性类型作为它的ModelType属性。属性IsComplexType和IsNullableValueType分别表示以ModelType属性表示的Model类型是一个复杂类型和可空值类型。

在这里判断某个类型是否是复杂类型的条件只有一个,即是否允许字符串类型向该类型的转换。具体来说,将通过ModelType属性表示的Model类型作为传输传入TypeDescriptor的静态方法GetConverter得到一个TypeConverter对象,如果TypeConverter不支持从字符串类型的转换则认为是复杂类型。所以所有的基元类型(Primative Type)均不是复杂类型,所有可空值类型(Nuallable Type)均不是是复杂类型。对于一个默认为复杂类型的自定义的数据类型,我们可以通过TypeConverterAttribute特性标注一个支持从字符串类型转换的TypeConverter使之转变成非复杂类型。

如下面的代码片断所示,我们定义了一个表示二维坐标的Point类型,由于我们在该类型上应用了一个TypeConverterAttribute特性指定了类型为PointTypeConverter的TypeConverter。由于PointTypeConverter支持从字符串到Point类型之间的转换,所以Point并不是一个复杂类型。
[chsarp]
1: [TypeConverter(typeof(PointTypeConverter))]

2: public class Point

3: {

4: public double X { get; set; }

5: public double Y { get; set; }

6: public Point(double x, double y)

7: {

8: this.X = x;

9: this.Y = y;

10: }

11: public static Point Parse(string point)

12: {

13: string[] split = point.Split(‘,’);

14: if(split.Length != 2)

15: {

16: throw new FormatException(“Invalid point expression.”);

17: }

18: double x;

19: double y;

20: if (!double.TryParse(split[0], out x) ||

21: !double.TryParse(split[1], out y))

22: {

23: throw new FormatException(“Invalid point expression.”);

24: }

25: return new Point(x, y);

26: }

27: }

28: public class PointTypeConverter : TypeConverter

29: {

30: public override bool CanConvertFrom(ITypeDescriptorContext context,

31: Type sourceType)

32: {

33: return sourceType == typeof(string);

34: }

35:

36: public override object ConvertFrom(ITypeDescriptorContext context,

37: CultureInfo culture, object value)

38: {

39: if (value is string)

40: {

41: return Point.Parse(value as string);

42: }

43: return base.ConvertFrom(context, culture, value);

44: }

45: }
[/csharp]

通过上面的介绍我们知道表示Model元数据的ModelMetadata具有一个树形的层次结构,某个节点可以看成了其子节点的容器, 而ContainerType这是表述容器的类型。同样以前面定义的Contact类型为例,基于该类型本身的ModelMetadata是整个层次树的 根节点,所以ContainerType返回Null;基于属性Address的ModelMetadata的ContainerType属性返回 Contact类型;而基于Address的属性Province的ModelMetadata的ContainerType属性值则是Address类 型。

ModelMetadata的Model属性代表的是作为Model的对象。如果将上面定义的Contact对象作为View的Model,那么表 示该Model本身元数据的ModelMetadata对象来说,其Model属性就是该Contact对象;对于基于Contact某个属性的 ModelMetadata对象则将对应的属性值作为自己的Model。值得一提的是,该属性是可读可写的,意味着我们可以随时根据需要改变它。另一个属 性PropertyName表示对应的属性值,对于根节点ModelMetadata来说,该属性总是返回Null。

ModelMetadata的AdditionalValues属性返回一个字典对象,用于存储一些自定义的属性,字典元素的Key和Value分别代表自定义属性的名称和值。对于自定义属性的添加,我们可以在数据类型或者其数据成员上应用AdditionalMetadataAttribute特性来实现。如下面的代码片断所示,AdditionalMetadataAttribute具有Name和Value两个只读属性分别表示自定义属性的名称和值,它们直接通过构造函数进行初始化。AdditionalMetadataAttribute实现了IMetadataAware接口,对于Model元数据的定制来说,这是一个非常重要并且实用的接口,我们将在下篇对其进行单独介绍。

1: [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Property |

2: AttributeTargets.Class, AllowMultiple=true)]

3: public sealed class AdditionalMetadataAttribute : Attribute, IMetadataAware

4: {

5: public AdditionalMetadataAttribute(string name, object value);

6: public void OnMetadataCreated(ModelMetadata metadata);

7: public string Name { get; }

8: public object Value { get;}

9: }

ModelMetadata的属性Provider是一个ModelMetadataProvider对象,顾名思义,ModelMetadataProvider是ModelProvider的提供者。ModelProvider是ASP.NET MVC整个Model元数据系统的核心,我们将在后续的博文中对其进行单独讲述。

[转载].NET性能分析如何找出使用过多内存的.NET代码

mikel阅读(1040)

[转载].NET性能分析最佳实践之:如何找出使用过多内存的.NET代码(基础篇) – 小洋(燕洋天) – 博客园.

 .NET性能分析最佳实践之:如何找出使用过多内存的.NET代码(基础篇

       在.NET应用中一个常常影响性能的因素就是代码消耗了过多的内存。很多的开发人员在编写代码的过程中常常不会关注性能,从而使得应用程序中到处存在性能 瓶颈。很多的时候,开发人员关注的总是代码的执行时间的长短,而把真正的性能问题丢掉了一边。在本篇文章中,我们将会找出代码中的哪些功能消耗了多少内 存。

              

本篇文章比较简单,我们会主要详细的介绍CLR Profiler这个工具。

 

 系列文章:

.NET性能分析最佳实践之:如何找出使用过多内存的.NET代码(进阶篇

 

 

本篇议题如下:

基础篇:详解介绍Profiler的使用

进阶篇:调用Profiler的API进行

 

基础篇:详解介绍Profiler的使用

       大家可以从这里从微软的站点下载CLR Profiler。一旦下载CLR Profiler之后,我们就可以解压,然后运行Bin文件夹中的“CLRProfiler.exe”。

首先我们来介绍一下CLR Profiler的功能。

       CLR Profiler确实是一个不错的工具,通过使用它,我们可以了解一个.NET应用程序到底是如何使用内存的,基本上面它的功能可以分为两类,如图所示:

 

20120409210650.png

 

1. 对一个.NET应用中的内存是如何分配的给出一个完整的描述。所以,我们可以看到每一种类型,方法所占用的内存情况。

2. 它告诉我们一个方法被调用了多少次。

 

       这里需要注意的就是:不要再生产环境或上面的服务器站点中运行CLR Profiler,因为它会严重的影响程序的影响。例如,如果我们的应用程序中包含两个方法,fun1和fun2,此时当我们运行CLR Profiler的时候,它会将一些逻辑注入到应用程序中,通过下面的一个图就可以很清楚的看出这个问题:

 

20120409210755.png

 

 

说了这么多,我们还是来看看,如何使用CLR Profiler。

       首先,在使用CLR Profiler之前,我们要清楚:要使用这个工具来干嘛?基本上,有两点理由:查看内存的分配与使用的情况;查看方法被调用次数。

启动了CRLProfiler.exe之后,选择要检查的程序,如下图:

 

20120409210842.png

 

此时,应用程序就开始运行,我们就可以在Profiler中看到一些信息,例如应用程序占用的内容,每一代对象占用的大小等,如下:

 20120409210929.png

 

       其实上面的那个应用程序非常的简单,只是作为一个demo演示而言。上面的程序的功能就是在一个按钮的事件中调用了两个方法:UseSimpleStringsUseStringBuilders。这个两个方法都是在拼接字符串(这也是常常被用来做例子的一个场景),我们分别让它们拼接1000个字符串,如下:

 

20120409211022.png

 

 

其中UseSimpleStrings如下:

 

20120409211053.png

 

UseStringBuilders如下:

 

20120409211127.png

       现在,我们可以尝试着使用Profiler去看看每个方法使用多少的内存。我们在程序中点击按钮,好让Profiler去收集信息。然后,我们在点击 Profiler的“histogram”按钮,此时我们就可以看到程序中的每一种类型的内存占用情况,如下:

 

20120409211321.png

如果我们想看每一个方法在运行过程中占用的内容,可以点击“Allocation Graph”,如下:

 

20120409211413.png

 

通过这个操作,我们可以看到下面的图:

 

20120409211458.png

 

       乍一看,可能感觉界面非常的混乱,特别是在应用程序很大的时候。为了更加看到我们想看的方法,我们可以通过在界面的中点击右键,点击“Find Routine”,然后选择输入过滤的条件,如下:

 

20120409211523.png

 

这样就可以快速的定位,如下:

 

20120409211559.png

 

然后在方法上面双击,就进一步的展开,查看细节,如下:

 

20120409211642.png

 

       在上图中,我们只是看到了“UseSimpleStrings”方法的使用内存的情况,因为这个界面显示的信息比较的粗糙,只是把一些内存使用比较多的方法列出来了,我们可以通过点击“0(everything)”查看所以的方法,此时看到如下:

 

20120409211717.png

 

通过上面的图,我们一目了然的直到内存的使用情况。

[转载]充分利用移动设备实现真正的无压工作

mikel阅读(879)

[转载]我的时间管理——充分利用WindowsPhone、Android等设备,实现真正的无压工作! – 刘水镜 – 博客园.

一寸光阴一寸金,寸金难买寸光阴。时间有多么珍贵,不用我多说大家都非常清楚。光知道时间的珍贵是不够的,重要的是我们如何合理的安排自己的时间。让每一分每一秒都过得有价值!

 

时间管理

 

我们已经进入了一个信息化的时代,大多数的工 作都可以找到合适的工具帮我们完成。同样,管理时间制定计划也有非常好的工具。像什么谷歌日历、Hotmail日历、Outlook、飞信等等,我就不一 一列举了。类似的工具我也用过一些,感觉谷歌日历跟Hotmail日历是非常不错的。之前我一直用的是谷歌日历,但最近不知怎么谷歌经常无法同步,所以就 改用Hotmail日历了。其实这两者除了外观有点差别之外,功能与基本设定几乎完全一样,如下图,一天24小时可以在任何时间设定你要做的事情。

 

 

对一些有规律、经常重复的事情可以设置循环——按天、周、月、年等循环,非常的人性化。

 

 

另外还有多种提醒方式,包括电子邮件、电脑端或手机端弹出窗口提示、让你无论何时何地都能够及时收到提醒,不错过任何一件事情。

 

 

如果不方便用电脑的话,还可以同步到手机上。 如今智能手机正以龙卷风一般的势头席卷全球,目前Android手机平均日激活量已经超过50万台,再加上IOS、新兴的WindowsPhone、三星 的Bada系统、惠普的WebOS等等。几乎快达到人手一部的地步了。而每一部智能手机都具有很强大的日程管理功能。我们可以将谷歌日历或者 Hotmail日历同步到我们的手机上。

本人目前用的是微软的WindowsPhone,所以下面就以WindowsPhone为例

 

  

 

锁屏和开始界面都可以看到接下来要做或者正在做的事情,非常方便。

 

 

 

 

可以单独浏览每天的安排,也可以纵观整个月,把握整体的安排。

 

 

点击某个具体的事件可以对其进行编辑,如果是循环事件还可以选择编辑本次,还是编辑所有。如果在手机端进行更改日历同样会同步到服务器上,利用强大的云实现无缝链接。

 

有了以上这些强大的工具以后,安排时间制定计划已经不成问题。但是新的问题又来了,那就是我们制定了这些计划如何才能够很好的执行呢?

想要解决这个问题也不难,咱们往下看:

 

个人管理

 

说完了时间管理,下面我们说说个人管理。前面 的时间管理只是教我们怎么安排时间制定计划,而接下来要说的个人管理,是教我们如何按时保量的去完成我们所制定的计划。关于个人管理的方法有很多,例如普 瑞玛法则、番茄工作法等。这些方法所主张的观点都很相似,中心思想大概都是将一整天分为若干个时间片,在这些比较短的时间片里只做规定的事情,其他事情不 要做不去想。没结束一个时间片进行短暂的休息,连续几个时间片以后进行较长的休息与放松。从而达到在短时间内精神高度集中提高效率的目的。

下面我们就以普瑞玛法则为例简单的说一下:

 

 

普瑞玛法则

普瑞玛法则除了主张将时间分段以外,其更核心的思想如下:

普瑞马法则:就是如果把一件更难完成的事情放 在比较容易完成的事情前面做。那更难完成的事情就可以成为比较容易完成的事情的强化刺激。换句话说,把不愿意干的任务或者工作放在喜欢完成的任务之前。如 果经常完成困难的、有挑战性的任务,那么工作能力就会增长;相反的话,工作能力就要下降。也就是说,把好玩的事情留在后面做。

 

没错,把自己最喜欢,觉得最有意思的事情放到最后做,这样做起事情来回更加有盼头,更有动力。就像吃东西一样,如果先让你把你喜欢的东西吃了,那么你不喜欢吃的东西你还会去吃吗;相反,如果规定必须先把你不喜欢的东西吃完,才可以吃你喜欢的东西结果会完全不同。

 

这种方式在一开始的时候会有些困难,但只要稍 微费些力气坚持一下就会过去。注意:中途不可跳过某个不喜欢的事情,而去做自己喜欢的事情。普瑞玛法则对于改变惰性的生活方式有很好的效果,而且据说对于 经常有抑郁心情的人也颇有效果。普瑞玛法则还有很多具体的实施方式,这里就不一一列举了,如有兴趣请看考百度百科中的普瑞玛法则解释。

 

最后再为大家推荐一本很有名的关于时间管理的书——尽量去做:无压工作的艺术

[转载]JSONObject简介

mikel阅读(1109)

[转载]JSONObject简介 – 月月鸟0820 – 博客园.

本节摘要:之前对JSON做了一次简单的介绍,并把JSON和XML做了一个简单的比较;那么,我就在想,如果 是一个json格式的字符串传到后台,需要怎么对其处理?如果前台页面需要后台返回的是一个json的字符串,那么后台是怎么把json格式的字符串给拼 装起来的呢?JSON和XML是不是有某种联系,他们之间是不是可以互相转换?……带着这些问题,搜索了相关的资料,并自己实际动手操作,总算对这些问题 有了个比较清晰的认识。这些问题主要是通过JSONObject这个插件的jar包实现。

preparation

1.JSONObject介绍

JSONObject-lib包是一个beans,collections,maps,java arrays和xml和JSON互相转换的包。

2.下载jar包

http://files.cnblogs.com/java-pan/lib.rar

提供了除JSONObject的jar之外依赖的其他6个jar包,一共7个jar文件

说明:因为工作中项目用到的版本是1.1的对应jdk1.3的版本,故本篇博客是基于1.1版本介绍的。

对应此版本的javadoc下载路径如下:http://sourceforge.net/projects/json-lib/files/json-lib/json-lib-1.1/

目前最新的版本为2.4,其他版本下载地址为http://sourceforge.net/projects/json-lib/files/json-lib/

3.项目环境:

system:WIN7 myeclipse:6.5 tomcat:5.0 JDK:开发环境和编译用的都是1.5

项目结构如下:

说明本次用到的的文件只有工程目录json包下的JSONObject_1_3类和note.txt

4.class&method 基于1.1的API

做以下几点约定:

1.介绍基于JSONObject 1.1的API

2.只介绍常用的类和方法

3.不再介绍此版本中已经不再推荐使用

4.介绍的类和方法主要围绕本篇博客中用到的

JSONObject:A JSONObject is an unordered collection of name/value pairs.

是一个final类,继承了Object,实现了JSON接口

构造方法如下:

JSONObject();创建一个空的JSONObject对象

JSONObject(boolean isNull);创建一个是否为空的JSONObject对象

普通方法如下:

fromBean(Object bean);静态方法,通过一个pojo对象创建一个JSONObject对象

fromJSONObject(JSONObject object);静态方法,通过另外一个JSONObject对象构造一个JSONObject对象

fromJSONString(JSONString string);静态方法,通过一个JSONString创建一个JSONObject对象

toString();把JSONObject对象转换为json格式的字符串

iterator();返回一个Iterator对象来遍历元素

接下来就是一些put/get方法,需要普通的get方法和pot方法做一下强调说明,API中是这样描述的:

A get method returns a value if one can be found, and throws an exception if one cannot be found. An opt method returns a default value instead of throwing an exception, and so is useful for obtaining optional values.

 

JSONArray:A JSONArray is an ordered sequence of values.

是一个final类,继承了Object,实现了JSON接口

构造方法如下:

JSONArray();构造一个空的JSONArray对象

普通方法如下:

fromArray(Object[] array);静态方法,通过一个java数组创建一个JSONArray对象

fromCollection(Collection collection);静态方法,通过collection集合对象创建一个JSONArray对象

fromString(String string);静态方法,通过一个json格式的字符串构造一个JSONArray对象

toString();把JSONArray对象转换为json格式的字符串

iterator();返回一个Iterator对象来遍历元素

接下来同样是put/get方法……

 

XMLSerializer:Utility class for transforming JSON to XML an back.

一个继承自Object的类

构造方法如下:

XMLSerializer();创建一个XMLSerializer对象

普通方法如下:

setRootName(String rootName);设置转换的xml的根元素名称

setTypeHintsEnabled(boolean typeHintsEnabled);设置每个元素是否显示type属性

write(JSON json);把json对象转换为xml,默认的字符编码是UTF-8,

需要设置编码可以用write(JSON json, String encoding)

 

5.对XML和JSON字符串各列一个简单的例子

JSON

{“password”:”123456″,”username”:”张三”}

xml

<?xml version=”1.0″ encoding=”UTF-8″?>
<user_info>

<password>123456</password>

<username>张三</username>

</user_info>

 

start

新建web工程,工程名称JS,导入以下7个jar包,文件在前面的准备工作中下载路径。

说明可以不用新建web工程,普通的java工程也可以完成本篇的的操作。至于为什么要导入处json包以外的其他6个包,我会把note.txt贴在最后,各位一看便知。

question1:后台接受到前台的json格式的字符串怎么处理?

1

 

question2:后台是怎么拼装json格式的字符串?

2

question3:json格式的字符串怎么转换为xml格式的字符串?

3

question4:xml格式的字符串怎么转换为json格式的字符串?

4

question5:javabean怎么转换为json字符串?

5

question6:javabean怎么转换为xml字符串?

6

 

完整的JSONObject_1_3.java代码如下:

JSONObject_1_3

完整的UserInfo.java代码如下:

UserInfo

 

result

代码和运行结果都已经贴在每个问题的后面,运行时直接用main方法分别对每个方法运行即可看到测试效果。

note.txt是报的对应的错误及解决方法,也从另一个方面说明为什么需要导入前面提到的jar包;

note.txt文件内容如下:

java.lang.NoClassDefFoundError: org/apache/commons/lang/exception/NestableRuntimeException
at java.lang.ClassLoader.defineClass0(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:537)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:123)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:251)
at java.net.URLClassLoader.access$100(URLClassLoader.java:55)
at java.net.URLClassLoader$1.run(URLClassLoader.java:194)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:187)
at java.lang.ClassLoader.loadClass(ClassLoader.java:289)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:274)
at java.lang.ClassLoader.loadClass(ClassLoader.java:235)
at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:302)
at generate.TestJSONObject.main(TestJSONObject.java:40)
Exception in thread “main”
解决方案:导入commons-lang-2.1.jar

java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory
at net.sf.json.JSONObject.<clinit>(JSONObject.java:125)
at generate.TestJSONObject.main(TestJSONObject.java:40)
Exception in thread “main”
解决方案:导入commons-logging.jar

java.lang.NoClassDefFoundError: org/apache/commons/beanutils/DynaBean
at net.sf.json.JSONObject.set(JSONObject.java:2164)
at net.sf.json.JSONObject.put(JSONObject.java:1853)
at net.sf.json.JSONObject.put(JSONObject.java:1806)
at generate.TestJSONObject.main(TestJSONObject.java:41)
Exception in thread “main”
解决方案:导入commons-beanutils.jar

java.lang.NoClassDefFoundError: net/sf/ezmorph/MorpherRegistry
at net.sf.json.util.JSONUtils.<clinit>(JSONUtils.java:65)
at net.sf.json.JSONObject.set(JSONObject.java:2164)
at net.sf.json.JSONObject.put(JSONObject.java:1853)
at net.sf.json.JSONObject.put(JSONObject.java:1806)
at generate.TestJSONObject.main(TestJSONObject.java:41)
Exception in thread “main”
解决方案:导入ezmorph-1.0.2.jar

java.lang.NoClassDefFoundError: org/apache/commons/collections/FastHashMap
at org.apache.commons.beanutils.PropertyUtils.<clinit>(PropertyUtils.java:208)
at net.sf.json.JSONObject.fromBean(JSONObject.java:190)
at net.sf.json.JSONObject.fromObject(JSONObject.java:437)
at net.sf.json.JSONObject.set(JSONObject.java:2196)
at net.sf.json.JSONObject.put(JSONObject.java:1853)
at net.sf.json.JSONObject.put(JSONObject.java:1806)
at generate.TestJSONObject.main(TestJSONObject.java:41)
Exception in thread “main”
解决方案:导入commons-collections-3.0.jar

Exception in thread “main” java.lang.NoClassDefFoundError: nu/xom/Serializer
at generate.TestJSONObject.jsonToXML(TestJSONObject.java:88)
at generate.TestJSONObject.main(TestJSONObject.java:96)
解决方案:导入xom-1.0d10.jar

 

几点说明:

1.注意UserInfo类的修饰符,用public修饰,变量username和password也用public修饰,最好单独的写一个类,这里就不贴出来了

2.以上json字符串和xml字符串都是最简单的形式,实际开发中json字符串和xml格式比这个复杂的多,

处理复杂的json字符串,可以封装写一个类继承HashMap,然后重写其put和get方法,以支持对类型为A[0].B及A.B的键值的读取和指定

3.以上6中情况在实际开发中可能有些不存在或不常用

 

存在的问题:

1.使用XMLSerializer的write方法生成的xml字符串的中文乱码问题

2.question4中的红色的log日志问题

2012-4-6 15:04:35 net.sf.json.xml.XMLSerializer getType
信息: Using default type string