[转载]利用LINQ 表达式实现跨服务器查询(大数据处理)

mikel阅读(950)

[转载]利用LINQ 表达式实现跨服务器查询(大数据处理) – lilin – 博客园.

在上一篇博文《利用LINQ 表达式实现跨服务器查询》提到可以联合查询跨服务器的两张表,

实现机制是查询到的实体类Order转化为集合,如代码:List<Order> ol = oq.ToList<Order>();

在利用其集合的扩展方法Join建立两个List的对应关系。如果这时数据量比较大,

就ToList<Order>这一句就十分耗性能了。如果是企业级的数据量,这种方法是行不通的。

那么有没有更好的方法呢?我想到了一种解决方案,与大家分享:

就上篇博文的例子,比如查询到的客户,我们只知道这些客户的定单就行的,其它客户定单没必要查询。查询到的客户如下列代码:
IQueryable<Customer> cq = from c in customer

                            where c.City == "Berlin"
                            select c;
LINQ TO SQL 表达式是预定义的,也就是先不执行,当然这里查询的数据只在一页上显示就行了。如果数量大可考虑分页问题。

下面就是关键的了,如何才能查询到客户的定单,用循环定单表吗?等于全表查询并扫描,不行。
我们知道在SQL 语句中 可用 Select * From Orders Where CustomerID ='ANATR' or CustomerID ='ALFKI'来实现我们要的结果
用LINQ 查询表达式这样写:
IQueryable<Order> oq = order.Where(o => o.CustomerID == "ANATR" || o.CustomerID == "ALFKI");
这种办法查询性能并不高。

SQL 语句 Select * From Orders Where CustomerID ='ANATR' Union All Select * From Orders Where CustomerID ='ALFKI'
要比上面的方法性能高多了,合理利用上了索引。
用LINQ 查询表达式这样写:
IQueryable<Order> oq = null;
foreach (Customer c in cl)
{
string v = c.CustomerID;
if (oq == null)
{
oq = order.Where(o => o.CustomerID == v);
}
else
{
oq = oq.Concat(order.Where(o => o.CustomerID == v));
}
}
List<Order> ol = oq.ToList<Order>();

上面代码意思就是循环客户表,建立类似Where CustomerID ='ANATR' 这样的条件,再用oq.Concat方法进行联接,
LINQ To SQL 会转化为下列的SQL语名。
可用odb.Log = Console.Out;语句在屏幕上打显示出来,如下:
---------------------------------------
SELECT [t4].[OrderID], [t4].[CustomerID], [t4].[OrderDate]
FROM (
SELECT [t2].[OrderID], [t2].[CustomerID], [t2].[OrderDate]
FROM (
SELECT [t0].[OrderID], [t0].[CustomerID], [t0].[OrderDate]
FROM [Orders] AS [t0]
WHERE [t0].[CustomerID] = @p0
UNION ALL
SELECT [t1].[OrderID], [t1].[CustomerID], [t1].[OrderDate]
FROM [Orders] AS [t1]
WHERE [t1].[CustomerID] = @p1
) AS [t2]
UNION ALL
SELECT [t3].[OrderID], [t3].[CustomerID], [t3].[OrderDate]
FROM [Orders] AS [t3]
WHERE [t3].[CustomerID] = @p2
) AS [t4]
-- @p0: Input NVarChar (Size = 5; Prec = 0; Scale = 0) [BOLID]
-- @p1: Input NVarChar (Size = 5; Prec = 0; Scale = 0) [FISSA]
-- @p2: Input NVarChar (Size = 5; Prec = 0; Scale = 0) [ROMEY]
-- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 3.5.30729.1
-----------------------------
这就是我的解决方法,不对之处请指正。欢迎与大家交流。

原文件下载:App2.rar

[转载]JQuery FlexiGrid的asp.net完美解决方案-dotNetFlexGrid使用指南(一)

mikel阅读(812)

[转载]JQuery FlexiGrid的asp.net完美解决方案-dotNetFlexGrid使用指南(一) – 华磊的空间 – 博客园.

  1. 简介

JQuery FlexiGrid的ASP.NET完美解决方案

dotNetFlexGrid是一款ASP.NET原生的异步表格控件,它的前身 是JQuery FlexiGrid插件,我们重构了FlexiGrid的大部分JavaScript代码,使其工作的更有效率,BUG更少;同时将其封装为 asp.net 控件,提供了简单易用的使用方式。

dotNetFlexGrid作为一个轻量级的表格控件,同时提供了大量实用和高效的功能:

  • 控件本身是全异步的工作模式,表格数据的刷新无需重新刷新整个页面。
  • 我们提供了若干易用的客户端方法,让你的程序在添加、修改、删除表格数据时无需重新加载大量的表格数据,而仅需要更新客户端展现结果,这样使得程序的后台访问次数大大降低。
  • 我们采用了类似AjaxPro的异步回调方式,使得您不必重新为异步请求单独开发页面,通过简单的数据提供函数,您能够在同一个页面中完成所有的表格异步操作。
  • dotNetFlexGrid提供了作为一个Grid应有的全部功能,包括表格排序、列拖动、首行的复选框、斑马色、快速查询、显示和隐藏列等等。
  1. 下载和配置
  2. 下载

您可以访问http://dotnetflexgrid.codeplex.com/ 下载控件的最新版本,包括最新的控件代码、演示项目和说明文档。

同时您可以访问http://www.cnblogs.com/hualei 获取控件的最新消息和使用指导,我们将为您提供最新的全中文的指导,同时我们欢迎您提供更好的建议和指正。

  1. 配置在您的项目中

请检查您下载的文件中包含dotNetFlexGrid v1.1.rar(此处采用v1.1版进行演示),该压缩包包含dotNetFlexGrid的全部源码,请将压缩包中的所有文件解压缩到如 dotNetFlexGridControl的目录(当然,您可以设定任意的文件夹名)。

根据您的项目情况,将dotNetFlexGridControl文件夹复制到您的asp.net站点目录的任意目录下,如果您使用的是Asp.net WebApplication,请在项目中至少包含如下文件:

  • dotNetFlexGridControl\dotNetFlexGrid.ascx
  • dotNetFlexGridControl\dotNetFlexGrid.ascx.cs
  • dotNetFlexGridControl\dotNetFlexGridAsyn.aspx
  • dotNetFlexGridControl\dotNetFlexGridAsyn.aspx.cs

请打开dotNetFlexGridControl\dotNetFlexGrid.ascx.cs文件,修改如下代码为您的项目中的控件路径。

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/// <summary>

/// 配置点:根据控件的实际路径配置

/// </summary>

public string ControlCurrentPath

{

get

{

// TODO:ControlCurrentPath 配置点:根据控件的实际路径配置

return “/dotNetFlexGridControl/”;

}

}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

同时,请在您的项目中引用Newtonsoft.Json.Net20.dll(该文件在Bin目录中提供)

一切完毕,现在您可以在您的项目中正式使用dotNetFlexGrid了。

Btw:似乎的确麻烦了点,现在dotNetFlexGrid是采用Asp.net用户控件的方式进行封装的,大多数的开发中测试均是使用的 Asp.net网站项目;在发布的时候,我们考虑到易用性以及便于修改,故没有采用自定义控件的方式进行封装;不过,这样似乎对使用者更加有利。

  1. 第一个Grid

好了,我们开始我们的第一个Gird,我们将实现演示项目中的FirstGrid.aspx的效果;这个例子展示一个模拟的用户列表。

首先,打开Visual Studio 2005/2008/2010;我们需要在页面中加入控件,将您的页面切换到设计视图(在源代码中复制粘贴也是不错的主意),从解决方案资源管理器找到控 件目录下的dotNetFlexGrid.ascx,直接拖拽到页面上合适的位置,注意检查下你的控件ID(本例直接使用默认的”dotNetFlexGrid1“)。

其次,我们需要写一段代码初始化Grid,将如下代码复制到你的页面的Page_Load中。

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

this.dotNetFlexGrid1.InitConfig(

new string[]{

“striped=true”,//是否显示行交替色

“selectedonclick=true”,//是否点击行自动选中checkbox

“usepager=true”,//使用分页器

“showcheckbox=true”,//显示复选框

“height=200”,//高度,可为auto或具体px值

“width=600”//宽度,可为auto或具体px值

},

new dotNetFlexGrid.FieldConfig[]{

new dotNetFlexGrid.FieldConfig(“Guid”,“编号”,60,true,dotNetFlexGrid.FieldConfigAlign.Left),

new dotNetFlexGrid.FieldConfig(“String1”,“用户名”,120,true,dotNetFlexGrid.FieldConfigAlign.Right),

new dotNetFlexGrid.FieldConfig(“String2”,“地址”,60,true,dotNetFlexGrid.FieldConfigAlign.Left),

new dotNetFlexGrid.FieldConfig(“String3”,“创建时间”,60,true,dotNetFlexGrid.FieldConfigAlign.Left)

}

);

//this.dotNetFlexGrid1.DataHandler = new dotNetFlexGrid.DataHandlerDelegate(DotNetFlexGrid1DataHandler); ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

dotNetFlexGrid1.InitConfig方法提供初始化表格主控参数、列配置的功能,例子中,我们设定表格宽600px,高 200px,并绑定 “编号””用户名””地址””创建时间”四个字段,自此,其实我们的Grid已经可以使用了,浏览该页面,我们看到了如下界面:

很简单,不是吗;我们看到了一个最简单的空表格,仔细看看,如此简单的表格其实拥有了如下强大的功能:

  • 您可以点击其中一列将其拖放到合适的位置上(当然仅限表头)。
  • 您可以将鼠标移动到列的分割线上,左右拖动来调整列宽。
  • 你可以将鼠标移动到表头的列的分割线左边,点击出现的按钮来选择需要显示和隐藏的列。
  • 您可以在表格的最左边和最下边拖动表格的大小。
  • 在表头移动鼠标,你会发现字段排序的指示(虽然现在没用:-)后面我们将用到它)。
  • 显示了内置的分页器和刷新按钮,当然,现在是无用的。

接下来,我们为表格填充数据,重新转到Page_Load中,我们增加一行,并在页面中增加一个提供数据的方法。

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

Page_Load中

this.dotNetFlexGrid1.DataHandler = new dotNetFlexGrid.DataHandlerDelegate(DotNetFlexGrid1DataHandler); //提供数据的方法

新增方法

public dotNetFlexGrid.DataHandlerResult DotNetFlexGrid1DataHandler(dotNetFlexGrid.DataHandlerParams p)

{

dotNetFlexGrid.DataHandlerResult result = new dotNetFlexGrid.DataHandlerResult();

result.page = p.page;//设定当前返回的页号

result.total = 100;//总计的数据条数,此处用100进行模拟

result.table = dotNetFlexGrid.DemoMemoryTable(p.page * 100, p.rp);//调用演示的数据生成函数产生模拟数据

return result;

}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

DotNetFlexGrid1DataHandler方法接收一个类型为dotNetFlexGrid.DataHandlerParams的参数,该参数提供控件的动作所产生的所有参数,如p.page(当前请求的页号)、p.rp(当前请求所希望返回的行数)等等,实际上,该参数包含众多的属性,具体请查看控件说明文档中的详细描述。

DotNetFlexGrid1DataHandler方法需要返回一个类型为dotNetFlexGrid.DataHandlerResult的对象,该对象必须提供属性page(当前返回的页号)、属性total(总共的数据条数)、属性table(包含数据的DataTable)。

在这里,我们模拟为Grid提供数据,我们使用控件内置的DemoMemoryTable()产生一个虚拟的DataTable,实际应用中,您需要根据您的需求构建储存数据的DataTable。

我们再次浏览页面,您会发现表格中填充了一些模拟的数据,同时分页器、排序功能、刷新功能均能正常使用了。

其实,我们会发现排序功能似乎无效,表格刷新后但并没有按照我们预期的进行排序,实际上,与其他控件不同,dotNetFlexGrid建议使用服 务端排序,大多数需求中,我们期望的排序功能是针对整个数据库查询的结果集进行排序,而大多数控件或JS 插件提供的仅仅是单页的客户端排序;既然这样,我们为这个例子增加排序处理,请修改你的DotNetFlexGrid1DataHandler方法。

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

public dotNetFlexGrid.DataHandlerResult DotNetFlexGrid1DataHandler(dotNetFlexGrid.DataHandlerParams p)

{

dotNetFlexGrid.DataHandlerResult result = new dotNetFlexGrid.DataHandlerResult();

result.page = p.page;//设定当前返回的页号

result.total = 100;//总计的数据条数,此处用100进行模拟

result.table = dotNetFlexGrid.DemoMemoryTable(p.page * 100, p.rp);//调用演示的数据生成函数产生模拟数据

//如果传递的参数包含排序设置的话,通过DataView.Sort功能模拟进行当页排序

if (p.sortname.Length > 0 && p.sortorder.Length > 0)

{

System.Data.DataView dv = result.table.DefaultView;

dv.Sort = (p.sortname + ” “ + p.sortorder);

result.table = dv.ToTable();

}

return result;

}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

好了,现在可以排序了,同时请原谅我又偷懒了,我们采用DataView.Sort功能模拟进行当前的数据集排序,实际上还是单页排序,但实际上, 此处的数据处理逻辑是应该连接数据库执行实际的查询,排序是否应该交给数据库?的确,分页和排序是很普遍的问题,我们在dotNetFlexGrid的说 明文档中同时提供了一个通用的分页、排序、查询的存储过程配套dotNetFlexGrid使用和参考,请大家自行下载。

最后,似乎还不够,一般我们的表格都会根据用户的条件更改查询结果,我们实现一个异步的查询效果。

我们在页面上增加一个id为”txtName”的文本框和id为”btnSubmit”的按钮以及一小段JavaScript,像下面这个样子。

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

<script language=”JavaScript”>

function doSearch() {

var txt = document.getElementById(“txtName”).value;

if (txt) {

var extP = [{ name: “String1”, value: txt}];

dotNetFlexGrid1.applyQueryReload(extP);

}

}

</script>

<div>

<input id=”txtName” type=”text” /> <input id=”btnSubmit” type=”button” value=”查询” onclick=”doSearch();”/>

</div> ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

更改下DotNetFlexGrid1DataHandler方法,让其支持查询。

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

public dotNetFlexGrid.DataHandlerResult DotNetFlexGrid1DataHandler(dotNetFlexGrid.DataHandlerParams p)

{

dotNetFlexGrid.DataHandlerResult result = new dotNetFlexGrid.DataHandlerResult();

result.page = p.page;//设定当前返回的页号

result.total = 100;//总计的数据条数,此处用100进行模拟

result.table = dotNetFlexGrid.DemoMemoryTable(p.page * 100, p.rp);//调用演示的数据生成函数产生模拟数据

//如果传递的参数包含排序设置的话,通过DataView.Sort功能模拟进行当页排序

if (p.sortname.Length > 0 && p.sortorder.Length > 0)

{

System.Data.DataView dv = result.table.DefaultView;

dv.Sort = (p.sortname + ” “ + p.sortorder);

result.table = dv.ToTable();

}

//如果传递的参数包含附加参数的话,再来模拟查询,原谅我真的很懒。

if (p.extParam.ContainsKey(“String1”))

{

System.Data.DataView dv = result.table.DefaultView;

dv.RowFilter = “String1 Like ‘%” + p.extParam[“String1”]+“%'”;

result.table = dv.ToTable();

}

return result;

}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

我们通过p.extParam获取到Javascript送出的查询数据(注意之前的js代码中的赋值和刷新表格),然后进行查询并返回结果集;其实,我们通过这种方法,可以很简单的实现与其他各类控件的联动,甚至无数个dotNetFlexGrid

Over,第一个例子到这里了,总结下:

  • 我们需要直接将控件拖拽入页面。
  • 在页面加载时调用InitConfig方法初始化Grid,我们在这里设置表格的宽、高、分页器等参数,同时设置表格需要展示的字段。
  • 为Grid绑定一个类型为dotNetFlexGrid.DataHandlerDelegate数据提供方法,我们在这个方法里响应Grid的动作并返回合适的结果。
  • 我们还可以通过简单的js调用异步控制我们的表格,例子中演示了异步查询和刷新。

不知不觉,似乎写了很多,其实dotNetFlexGrid是非常易用的,3个简单的步骤即可完成一个完全异步的Grid,足以替换掉Asp.net自带的GridView了。

下一次,我们将演示快速查询的功能以及2个表格的联动功能,敬请期待。

BTW:本文的例子包含在整个演示项目中,不幸的是,演示项目的下载需要稍后提供,当然,看到此文的都是多年的ASP.NET老手,如此简单的例子,相信不会给大家带来过多的困惑。

[转载]网上常用免费WebServices集合

mikel阅读(811)

[转载]网上常用免费WebServices集合 – Capricornus – 博客园.

天气预报Web服务,数据来源于中国气象局 公用事业
http://www.webxml.com.cn/WebServices/WeatherWebService.asmx

中国股票行情分时走势预览缩略图
http://www.webxml.com.cn/webservices/ChinaStockSmallImageWS.asmx

中国股票行情数据 WEB 服务(支持深圳和上海股市的基金、债券和股票)
http://www.webxml.com.cn/WebServices/ChinaStockWebService.asmx

国内飞机航班时刻表 WEB 服务 公用事业
http://www.webxml.com.cn/webservices/DomesticAirline.asmx

中国电视节目预告(电视节目表) WEB 服务 公用事业
http://www.webxml.com.cn/webservices/ChinaTVprogramWebService.asmx

火车时刻表 (第六次提速最新列车时刻表) 公用事业
http://www.webxml.com.cn/WebServices/TrainTimeWebService.asmx

中文 <-> 英文双向翻译 WEB 服务 获得标准数据
http://www.webxml.com.cn/WebServices/TranslatorWebService.asmx

验证码图片 WEB 服务 支持中文、字母、数字 图像和多媒体
http://www.webxml.com.cn/WebServices/ValidateCodeWebService.asmx

中国邮政编码 <-> 地址信息双向查询/搜索 WEB 服务 获得标准数据
http://www.webxml.com.cn/WebServices/ChinaZipSearchWebService.asmx

IP地址来源搜索 WEB 服务(是目前最完整的IP地址数据) 获得标准数据
http://www.webxml.com.cn/WebServices/IpAddressSearchWebService.asmx

国内手机号码归属地查询

http://webservice.webxml.com.cn/WebServices/MobileCodeWS.asmx

外汇-人民币即时报价

http://webservice.webxml.com.cn/WebServices/ForexRmbRateWebService.asmx

腾讯QQ在线状态 WEB 服务

http://webservice.webxml.com.cn/webservices/qqOnlineWebService.asmx

中文简体字<->繁体字转换 WEB 服务
http://webservice.webxml.com.cn/WebServices/TraditionalSimplifiedWebService.asmx

IP地址搜索 WEB 服务包含中国和国外已知的IP地址数据,是目前最完整的IP地址数据,记录数量现已超过37万条并还在不断更新和增加中
http://webservice.webxml.com.cn/WebServices/IpAddressSearchWebService.asmx

[转载]memCached客户端CPU过高问题的排查

mikel阅读(1491)

[转载]memCached客户端CPU过高问题的排查 – hellofox2000 – 博客园.

公司网站使用了memCached来做分布式缓存,最近有人反映memCached客户端占用CPU过高,怀疑是第三方客户端性能不佳,进而怀疑是文本协议的问题,要求部门自己开发memCached的客户端,使其支持二进制协议。因为重新开发客户端工作量比较大,同时在日常开发中,没有听说过memCached客户端遇到瓶颈。因此对此问题进行了排查。结果发现主要是由于客户端反序列化,类设计不合理造成的。把排查过程分享下,希望对其他人有所帮助。

首先想到是:memCached服务器端内存占满,在清理内存中,造成客户端socket连接不上,不断发生异常。随上服务器查看了memCached的内存占用率,连接数等,发现利用率均很低。暂时先排除服务器端问题。

其次想到可能是第三方在使用socket连接池时,造成资源没有关闭,或者死锁。随对第三方客户端代码粗略读了一遍,并搜索相关文档。未发现异常代码。暂时先排除第三方客户端问题。

最后想到会不会是开发人员在代码编写中出现了问题。随对反映问题的两个产品进行了排查。发现了以下代码。

代码片段1

代码

static Serializer ser = new Serializer(typeof(List<UserModule>)); //using JsonExSerializer;
public static List<UserModule> GetAllUserModule(int userId)
{
string cache = CacheManager.Current.Get<string>(GetCacheKey(userId));
if (!string.IsNullOrEmpty(cache))
{
return ser.Deserialize(cache) as List<UserModule>;
}
else
{
return null;
}
}

public static List<UserModule> SetAllUserModule(int userId, List<UserModule> modules)
{
if (modules != null)
{
string cache = ser.Serialize(modules);
CacheManager.Current.Add(GetCacheKey(userId), cache);
}
else
{
CacheManager.Current.Remove(GetCacheKey(userId));
}
return modules;
}

代码片段2

代码

/// <summary>
/// 聊天室房间
/// </summary>
[Serializable]
public class Room
{
//房间有观看人员数据
List<Viewer> _viewers = null;
List
<string> _blackips = null;
List
<Viewer> _blackviewers = null;
List
<Notice> _notice = null;
List
<Speaker > _speakers = null;
List
<Content> _content = null;

/// <summary>
/// 添加新聊天者
/// </summary>
/// <returns>返回新添加的聊天人员</returns>
public Viewer AddViewer()
{
Viewer vi
= new Viewer();
//MaxViewerID += 1;

//int id = MaxViewerID;
int id = GetViewerID();
vi.Name
= GetViewerName(游客 + id);
//vi.IP = System.Web.HttpContext.Current.Request.UserHostAddress;
vi.IP = 127.0.0.1;
vi.ViewID
= id;
Viewers.Add(vi);
return vi;
}

/// <summary>
/// 添加聊天内容
/// </summary>
/// <param name=”content”>聊天的内容</param>
/// <param name=”viewid”>发言人的id</param>
/// <returns>返回新添加的对象</returns>
public Content AddContent(string content, int viewid)
{
MaxContentID
+= 1;
Content con
= new Content(DateTime.Now, content, viewid, MaxContentID);
Contents.Add(con);
return con;
}
……
}

调用代码为:
Room room = LiveSys.Get(key);
lock (room)
{
if (room.MaxContentID == 0)
{
//ChatContentOp cpo = new ChatContentOp();
//room.MaxContentID = cpo.GetMaxContentID();

room.MaxContentID
= 300;
}
int viewerID = 123124123;
room.AddContent(chatContent, viewerID);
//判断内容是否大于100条。如果大于100条,删除最近的100条以外的数据。
System.IO.File.AppendAllText(@”d:\haha.txt, 最大数值: + room.LimitContentCount + ###############聊天记录数: + room.Contents.Count + \r\n);
if (room.Contents.Count > room.LimitContentCount)
{
room.Contents.RemoveRange(
0, room.Contents.Count room.LimitContentCount);
}
}
LiveSys.Set(key, room);

代码1存在的问题是:

Cache存储的参数类型为object,没有必要先进行一次序列化,然后再进行存储。而序列化是很消耗CPU的。

代码2问题:

代码2实现的是一个在线聊天室,聊天室本身含有访客,发言等内容。在发言时,对聊天室内容进行判断,只显示最近30条。新进来访客直接加到访客别表中。表面上是没什么问题的。但是细想之下有两个问题:

1 聊天室类设计的比较复杂,每次从memCached服务端取得数据后,都要进行类型转换。

2 没有访客清理机制。随着访客的不断进入,对象的体积会不断增大。

对存疑部分编写了代码进行测试。测试结果果然如推测所想。测试结果如下:

场景 写入 读取 大小

(单位)

CPU
次数 时间 平均 次数 时间 平均
本地缓存 10000 0.03125 0 10000 0 0 1k 0
MemClient 10000 19.2656 0.001926 10000 22.75 0.002275 1k
Json1k 1000 2.8437 0.002843 1000 5.375 0.005375 1k
Json8k 1000 3.8593 0.003859 1000 29.0312 0.029031 8k
直播1000人次 1000 38.9375 0.038937 1000 50k
直播8000人次 100 18.25 0.1825 100 350k
500k 100 7.375 0.07375 100 7.09375 0.070937 500k
场景 写入 读取 大小

(单位)

CPU
次数 时间 平均 次数 时间 平均
本地缓存 10000 0.03125 3.125E-06 10000 0.015625 1.5625E-06 1k 0
MemClient 10000 19.78125 0.001978 10000 21.953125 0.002195 1k
Json1k 1000 2.03125 0.002031 1000 6.078125 0.006078 1k
Json8k 1000 2.765625 0.002765 1000 55.375 0.055375 8k
直播1000人次 1000 38.53125 0.038531 1000 50k
直播8000人次 100 17.96875 0.179687 1000 350k
500k 100 7.5 0.075 100 6.5625 0.065625 500k
场景 写入 读取 大小

(单位)

CPU
次数 时间 平均 次数 时间 平均
本地缓存 10000 0.015625 1.5625E-06 10000 0.015625 1.5625E-06 1k 0
MemClient 10000 18.015625 0.001801 10000 25.96875 0.002596 1k 6%
Json1k 1000 1.15625 0.001156 1000 3.078125 0.003078 1k 40%
Json8k 1000 1.859375 0.001859 1000 32.484375 0.032484 8k 50%
直播1000人次 1000 45.046875 0.045046 1000 50k 30-40%
直播8000人次 100 31.703125 0.317031 100 350k 50%
500k 100 7.0625 0.070625 100 6.421875 0.064218 500k 6%

直播1000人次(当天一共有1000人访问,数据来源于运营检测),留言内容为30条时,Room体积大概为:57K


直播1000人次(当天一共有8000人访问,数据来源于运营检测),留言内容为30条时,Room体积大概为:350k

根据图表可以看到以下情况:处理时间、CPU利用率和数据量大小,序列化,类复杂性都有关系。

序列化问题(类型转换)对性能影响最为明显(可在场景”json1k”、场景直播中看到)。在Json1k中,存储对象和前几个场景是相同的,处理时间也相差不大,较大区别是CPU利用率由5%左右增长到40%左右(反序列化时尤为明显)。在场景直播系统中,不存在序列化问题,但是其对象属性中存在访客繁衍等多个复杂对象,造成其在处理时需要处理过多的类型转换,同时其体积不断增大。

存储对象的大小和处理时间存在一定关系,例如场景”500k”,其处理时间增长,但是其CPU利用率并未提高,其时间增长是由于对象传输造成。

本地缓存在内存中进行寻址和类型转换,涉及不到Socket连接,网络传输,序列化操作,所以其处理相当快。

就测试结果看:

本地缓存性能大约是分布式缓存性能的100倍左右。而出问题的聊天室除了CPU增高以外,其性能更比分布式缓存再降低40倍(直播1000人次)到200倍(直播8000人次)。综合来看,聊天室的分布式缓存比本地缓存降了4000倍,甚至更多。

但是,还没有完。

对于第二个问题,更改类设计,清楚无效访客,即可解决。

但是第一个问题,为什么用户在存储之前,先进行json序列化呢?嗯,这是一个问题。

遂问之。

答曰,有些类直接使用第三方客户端存储时,直接存储报错,所以先序列化为json类型,取值时再反序列化回来。

嗯,还有这事?

开发人员说了相关代码。

代码

interface IUser
{
String UserId{
get; set;}
String UserName{
get; set;}
}

[Serializable]
class UserInfo : IUser
{
String UserId{
get; set;}
String UserName{
get; set;}
}
[Serializable]
class Game
{
IUser User{
get; set;}
String UserName{
get; set;}
}

他说:Game对象在直接使用memCachedClient时,是不能被二进制序列化的,因为其User属性类型为IUser,为一个接口。因此想了一个解决方法,即先将Game对象进行 json序列化将其变为字符串,然后将字符串存储到memCached

原来是这样。

接着又查看了memCachedClient源代码,其需要将对象进行二进制序列化,然后进行存储。接口属性不能被序列化,遂又对序列化问题进行了测试(见附件)。测试结果显示上述代码直接进行二进制序列化是可以的,同时直接使用第三方客户端也是可以可行的。

问题出在哪?难道是没有加[Serializable]

一查果然:一个Serializable引发的血案。。。

记得有人说过,慎用分布式,能不用尽量不用。

一方面在性能上确实下降很多,分布式存储主要性能消耗在以下几个方面:协议解析,Socket连接,数据传输,序列化/类型转换。

一方面在使用场景和类设计上要求也更加严格。个人认为memCached是不太适合存储特别大的文件的。虽然有人说网上已经有用来存储视频的。

还有几个问题希望知道的朋友回答下:

1 有没有.Net方面的memCached客户端支持二进制协议和一致性的?

2 测试中发现,当memCached设置缓存过小时(例如64M),当其内存使用已经到62M时,再进行存储,新存储的内容再取出来就是空值,不知道是什么原因。

文章中用到的源码:下载源码

[转载]使用IIS内置压缩功能,增加网站访问速度

mikel阅读(1034)

[转载]使用IIS内置压缩功能,增加网站访问速度 – Capricornus – 博客园.

HTTP 压缩是在Web服务器和浏览器间传输压缩文本内容的方法。HTTP压缩采用通用的压缩算法如gzip等压缩HTML、JavaScript或CSS文件。压缩的最大好处就是降低了网络传输的数据量,从而提高客户端浏览器的访问速度。当然,同时也会增加一点点服务器的负担。Gzip是比较常见的一种HTTP 压缩算法。

默认的IIS中是有GZIP.dll组件的,我们只要开启即可.操作步骤如下:

1.开启HTTP压缩功能

在IIS中右键网站属性->服务选项卡->选中<压缩应用程序文件><压缩静态文件>两个选项.如图

2.在Web服务扩展中增加一个新扩展

右键Web服务扩展->增加一个新的Web服务扩展->要求的文件C:\WINDOWS\system32\inetsrv\gzip.dll ->设置扩展状态为允许.如图

3.修改IIS配置文件 (注意: 一定要先备份MetaBase.xml文件)

1).打开C:\Windows\System32\inetsrv\MetaBase.xml文件.

2).使用ctrl+f查找 Location =”/LM/W3SVC/Filters/Compression/gzip”与      Location =”/LM/W3SVC/Filters/Compression/deflate”

3).将两个节点的配置修改为如下配置

代码

<IIsCompressionScheme Location ="/LM/W3SVC/Filters/Compression/deflate" HcCompressionDll="%windir%\system32\inetsrv\gzip.dll" HcCreateFlags="0" HcDoDynamicCompression="TRUE" HcDoOnDemandCompression="TRUE" HcDoStaticCompression="true" HcDynamicCompressionLevel="9" HcFileExtensions="htm html txt js css swf xml" HcOnDemandCompLevel="9" HcPriority="1" HcScriptFileExtensions="asp aspx dll exe" > </IIsCompressionScheme> <IIsCompressionScheme Location ="/LM/W3SVC/Filters/Compression/gzip" HcCompressionDll="%windir%\system32\inetsrv\gzip.dll" HcCreateFlags="1" HcDoDynamicCompression="TRUE" HcDoOnDemandCompression="TRUE" HcDoStaticCompression="true" HcDynamicCompressionLevel="9" HcFileExtensions="htm html txt js css swf xml" HcOnDemandCompLevel="9" HcPriority="1" HcScriptFileExtensions="asp aspx dll exe" > </IIsCompressionScheme>

其中HcFileExtensions中是需要静态压缩的后缀,你也可以添加doc,xsl等文件内容

HcScriptFileExtensions 则是动态压缩的后缀

4.修改完毕后,保存文件,重启IIS即可.(如果无法保存,代表IIS正在使用中,可以先关闭IIS服务)

另外GZIP检测地址为:http://tool.chinaz.com/Gzips/

可以看出博客园也是进行过GZIP加速的:

[转载]ASP.Net MVC教程之《在15分钟内用ASP.Net MVC创建一个电影数据库应用程序》

mikel阅读(877)

[转载]ASP.Net MVC教程之《在15分钟内用ASP.Net MVC创建一个电影数据库应用程序》 – JasenKin – 博客园.

在15分钟内用ASP.NET MVC创建一个电影数据库应用程序

Stephen Walther 从头开始到结束建立了整个数据驱动ASP.NET MVC应用程序。这个教程对于那些刚刚接触ASP.NET MVC框架以及想要获得一种建立ASP.NET MVC应用程序的过程的新人是一个很好的介绍。
这个教程的目的就是给你一种“它会是什么样子”去创建ASP.NET MVC应用程序的理念。在这一课中,从开始到结束,我将直接建立一个完整ASP.NET MVC应用程序。我向你展示如何建立一个简单的数据驱动应用程序,演示如何列出,创建和编辑数据库记录。

为简化创建应用程序的过程,我们会充分利用Visual Studio 2008的功能。我们会让 Visual Studio为我们的控制层,模型层,视图层生成初始代码和内容。

如果你已经使用Active Server Pages 或者 ASP.NET来工作,那么你将对ASP.NET MVC很熟悉。ASP.NET MVC 视图与ASP应用程序的页面非常相似。并且与传统的ASP.NET Web Forms 应用程序一样, ASP.NET MVC 为你提供了丰富的语言和.NET框架类。我希望这篇教程将让你了解到创建ASP.NET MVC应用程序的经验与创建ASP or ASP.NET Web Forms 应用程序的相似点和不同点.

这部电影数据库应用程序的概述

因为我们的目标是让事情简单化,我们将建立一个非常简单的电影数据库应用程序。我们的简单的电影的数据库应用程序将使我们能够做的三件事:

1。列出一系列电影数据库记录
2。创建一个新的电影数据库记录
3。编辑一个现有的电影数据库记录
再次,因为我们想让事情变得简单,我们会利用ASP.NET MVC框架少量的特点来建立我们的应用程序。例如,我们不会利用测试驱动开发。

为了创造我们的应用程序,我们需要完成下列步骤:

1。建立 ASP.NET MVC Web Application 项目
2。创建数据库
3。创建数据库模型层
4。建立ASP.NET MVC控制层
5。建立ASP.NET MVC视图层

篇前部分(准备工作)
你将需要Visual Studio 2008 或者 Visual Web Developer 2008 Express来建立一个 ASP.NET MVC 应用程序。你还需要下载 ASP.NET MVC  MVC框架。

如果你还没有安装Visual Studio 2008,你可以从这个网站下载一个90天试用版的Visual Studio 2008:
http://msdn.microsoft.com/en-us/vs2008/products/cc268305.aspx

或者,你可以使用Visual Web Developer Express 2008创建ASP.NET MVC应用程序。如果你决定要用Visual Web Developer Express ,你就必须已经安装 Service Pack 1 。你可以从这个网站下载Visual Web Developer 2008 Express with Service Pack 1 :

http://www.microsoft.com/downloads/details.aspx?FamilyId=BDB6391C-05CA-4036-9154-6DF4F6DEBD14&displaylang=en

在你安装完Visual Studio 2008 或者 Visual Web Developer 2008以后,你需要安装ASP.NET MVC 框架。你可以从以下网站下载ASP.NET MVC 框架:

http://www.asp.net/mvc/

创建一个ASP.NET MVC Web Application 项目
让我们使用 Visual Studio 2010创建ASP.NET MVC Web Application项目来开始。选择菜单选择文件,新建,项目,你将会看到这个新项目的对话框。选择C#作为编程语言以及选择ASP.NET MVC 2 Web 应用程序项目模板。给你的项目命名为MovieApp和点击“确定”按钮。

图1

当你创建一个新的MVC Web Application项目时 Visual Studio提示你去创造一个独立的单元测试项目,如图2所示。因为在这一课中我们不会创建测试,选择“否”选项,并点击“确定”按钮。

图2

ASP.NET MVC应用程序有一系列标准的文件夹:模型、视图和控制的文件夹。你可以在“解决方案资源管理器”中看到这一系列标准的文件夹。我们需要添加文件到模型层,视图层和控制层文件夹,用以创建我们的电影的数据库应用程序。

当你使用Visual Studio创建一个新的MVC应用程序,你得到了一个示例应用程序。因为我们要从头开始,我们需要删除该示例应用程序的内容。你需要删除以下的文件和文件夹。
•Controllers\HomeController.cs
•Views\Home
创建数据库
我们需要创建一个数据库来保存我们的电影数据库记录。幸运的是,Visual Studio包含一个免费的SQL Server Express。遵循这些步骤来创建数据库。

1。在“解决方案终于管理器”中,右键点击该App_Data文件夹,选择菜单的选项“添加”,“新建”。
2。选择数据分类和选择SQL Server数据库模板(见图3)。
3。命名新数据库MoviesDB.mdf,然后点击“增加”按钮。
在你创造你的数据库后,你可以双击位于App_Data文件夹中的MoviesDB.mdf文件来连接这个数据库。双击MoviesDB.mdf文件,打开服务器资源管理器的窗口。
图3

接下来,我们要创造一个新数据库表。从服务器资源管理器窗口,右键点击该表格的文件夹“表”,并选择菜单选项“添加新表”。选择这个菜单选项打开数据库

表设计器。创建以下数据库的栏目。

第一列,Id列,有两个特殊的属性。首先,你需要标记Id列为主键列。选择 后,点击Id列的“设置主键”选项(它是图标看起来像一个钥匙)。其次,你需要标记Id列作为一个标记列。在这个“列属性”窗口,向下转动滚轮至“标识规 范”并且展开该节点,改变“(是标识)”为“是”。当你完成,表应该看起来像图4。

图4

最后一步是保存这个新表。点击“保存按钮,并且给新表命名为Movies。

当你完成创建表,加上一些电影记录到这个表格中。在服务器资源管理器中,右键点击Movies表,选择菜单选项显示表的数据。输入你最喜欢的电影清单(见图5)。

创建模型层
我们下一步要创建一系列的类来代表我们的数据库。我们需要创建一个数据库模型。我们将充分利用微软实体框架来自动生成我们的数据库模型。

ASP.NET MVC 框架与微软实体框架是无关联的。你可以通过很多的对象-关系映射(OR/ M)工具来创建你的数据库模型类,其中包括LINQ to SQL, Subsonic、NHibernate。

遵循这些步骤来展开实体数据模型向导。

1。在解决方案资源管理器窗口中,右键点击该模型层的文件夹,选择“添加”,“新建项”。
2。选择“数据”分类和选择ADO.NET 实体数据模型模板。
3。将你的数据模型命名为MoviesDBModel.edmx,然后点击“添加”按钮。

图7

你点击“添加”按钮后,这个实体数据模型向导出现(见图)。遵循这些步骤来完成向导。

1。在选择模型内容这一步,选择“从数据库生成”的选择。
2。在选择你的数据连接这一步,使用这个MoviesDB.mdf数据连接以及MoviesDBEntities作为连接设置。单击下一步按钮。

图8
3。在选择你的数据库对象一步,扩大表节点,选择Movies表。输入的命名空间MovieApp,单击“完成”按钮。

图9

在你完成实体数据模型向导,实体数据模型设计器将开启。设计器应该显示 Movies数据库表(见图10)。

在我们继续之前,我们需要做一点改变。这个实体数据向导生成一个Movies的模型类,代表 Movies数据库表。因为我们将使用这个 Movies 类代表某一特定的电影,我们需要修改这个类的名称为Movie而不是Movies(单数而不是复数)。

在设计器的表面,双击这个类的名称以及更改这个类名为Movie。在标识这个更改以后,点击保存按钮来生成Movie类。

创建ASP.NET MVC 控制层
下一步是要创建这个ASP.NET MVC 控制层。一个控制层负责控制用户和 ASP.NET MVC 应用程序的相互作用。

遵循这些步骤:

1。在解决方案资源管理器中,右键点击该 Controllers文件夹,并选择菜单选项“添加控制器”。
2。在对话框中输入框中,键入HomeController和勾选“为Create,Update…”
(见图11)。

3。点击“添加”按钮来添加新的控制器。
在您完成这些步骤,该控制器在Listing 1就创建了。注意到它包含的Index, Details, Create, and Edit这些方法。在接下来的章节,我们将添加所需的代码来使这些方法来工作。
Listing 1 – Controllers\HomeController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace MovieApp.Controllers
{
public class HomeController : Controller
{
//
// GET: /Home/

public ActionResult Index()
{
return View();
}

//
// GET: /Home/Details/5

public ActionResult Details(int id)
{
return View();
}

//
// GET: /Home/Create

public ActionResult Create()
{
return View();
}

//
// POST: /Home/Create

[HttpPost]
public ActionResult Create(FormCollection collection)
{
try
{
// TODO: Add insert logic here

return RedirectToAction(“Index”);
}
catch
{
return View();
}
}

//
// GET: /Home/Edit/5

public ActionResult Edit(int id)
{
return View();
}

//
// POST: /Home/Edit/5

[HttpPost]
public ActionResult Edit(int id, FormCollection collection)
{
try
{
// TODO: Add update logic here

return RedirectToAction(“Index”);
}
catch
{
return View();
}
}

//
// GET: /Home/Delete/5

public ActionResult Delete(int id)
{
return View();
}

//
// POST: /Home/Delete/5

[HttpPost]
public ActionResult Delete(int id, FormCollection collection)
{
try
{
// TODO: Add delete logic here

return RedirectToAction(“Index”);
}
catch
{
return View();
}
}
}
}
列出数据库记录
这个Home controller中的Index()方法是ASP.NET MVC 应用程序的默认的方法。当你运行ASP.NET MVC 应用程序,该Index()方法是第一个被调用的控制器的方法

我们将使用 Index()方法来显示Movies数据库表的一些数据。我们将使用Index()方法,利用数据库模型类来检索Movies数据库记录。

在Listing 2,我已经修改了HomeController类 ,以便它包含了1个新的_db所有字段。MoviesDBEntities类代表我们的数据库模型,我们将使用这类与数据库通信。

在Listing 2,我还修改了Index()方法。这个Index()方法使用MoviesDBEntities类来检索Movies 数据库表的所有记录。表达式_db.MovieSet.ToList()返回Movies数据库表所有的记录列表。

这个movies的列表传递给view层。

Listing 2 – Controllers/HomeController.cs (修改的Index()方法)。

public class HomeController : Controller
{

//
// GET: /Home/

private MovieApp.Models.MoviesDBEntities _db = new

Models.MoviesDBEntities();
public ActionResult Index()
{
//return View();
return View(_db.Movies.ToList());
}
….
}
Index()方法将返回一个命名为Index的视图view。我们需要创建这个view来显示movies数据库记录的列表。遵循这些步骤:

在打开之前的对话或不加观课程将出现在视图数据等级的下拉列表。你应该生成你的项目(选择菜单选项“生成”,“生成解决方案”)
1。在代码编辑窗口中右键点击该Index()方法和选择菜单选项“添加视图”(见图13)。
2。在对话框的角度,勾选“创建强类型视图”复选框。
3。从“视图数据类”下拉列表中,选择值MovieApp.Models.Movie。
4。从“视图内容”下拉列表中,选择值List。
5。点击“添加”按钮来创造新的view(见图3)。
在您完成这些步骤,一个新命名Index.aspx的View被添加到Views\Home 目录。这个Index view的内容都包含在Listing 3.。

Listing 3 – Views\Home\Index.aspx

<%@ Page Title=”” Language=”C#

MasterPageFile=”~/Views/Shared/Site.Master”

Inherits=”System.Web.Mvc.ViewPage<IEnumerable<MovieApp.Models.Movie>>”

%>

<asp:Content ID=”Content1″ ContentPlaceHolderID=”TitleContent”

runat=”server”>
Index
</asp:Content>

<asp:Content ID=”Content2″ ContentPlaceHolderID=”MainContent”

runat=”server”>

<h2>Index</h2>

<table>
<tr>
<th></th>
<th>
Id
</th>
<th>
Title
</th>
<th>
Director
</th>
<th>
DateReleased
</th>
</tr>

<% foreach (var item in Model) { %>

<tr>
<td>
<%: Html.ActionLink(“Edit”, “Edit”, new { id=item.Id })

%> |
<%: Html.ActionLink(“Details”, “Details”, new {

id=item.Id })%> |
<%: Html.ActionLink(“Delete”, “Delete”, new {

id=item.Id })%>
</td>
<td>
<%: item.Id %>
</td>
<td>
<%: item.Title %>
</td>
<td>
<%: item.Director %>
</td>
<td>
<%: String.Format(“{0:g}”, item.DateReleased) %>
</td>
</tr>

<% } %>

</table>

<p>
<%: Html.ActionLink(“Create New”, “Create”) %>
</p>

</asp:Content>

这个Index view 将movie数据库表所有记录显示在HTML表格。这个视图包含一个foreach循环,它遍历ViewData.Model属性所表示的每一个 movie。如果你通过按F5键运行应用程序,你将会看到网页如图  所示。

图14

创建新的数据库记录

我们在前一部分创建 的Index view 包括一个为创建新数据库记录的链接。

Homecontroller包含两种 Create()方法。第一个的 Create()方法没有参数。这个重载的 Create()方法被用来显示HTML表单。

第二个Create()方法有一个FormCollection参数。当这个创建一个新的movie的HTML表单回传到服务器时,这个重载的 Create()方法将被调用。注意这第二个Create()方法有一个AcceptVerbs属性,它将阻止这个方法被调用,除非HTTP POST操作执行了。

这个第二个Create()方法已经在Listing 4更新过的HomeController类中被修改了。新版本的Create()方法接受一个Movie 参数和包含插入一个新的movie到movies数据库表的逻辑。

注意绑定属性。因为我们不想从HTML表单更新影片Id属性,我们需要明确排除该属性。
Listing 4 – Controllers\HomeController.cs (modified Create method)
//
// POST: /Home/Create
[AcceptVerbs(HttpVerbs.Post)]

public ActionResult Create([Bind(Exclude = “Id”)] Movie movieToCreate)
{

if (!ModelState.IsValid)

return View();

_db.AddToMovies(movieToCreate);
_db.SaveChanges();
return RedirectToAction(“Index”);

}

Visual Studio ,使它容易创建表格来创建一个新的movie数据库记录(见图)。遵循这些步骤:

1。在代码编辑窗口,右键单击Create()方法,选择菜单选项“添加视图”。
2。确认勾选“创建强类型视图”。
3。从“视图数据类”下拉列表中,选择值MovieApp.Models.Movie。
4。从“视图内容”下拉列表中,选择值 Create。
5。点击“添加”按钮来创造新的view(见图3)。


Visual Studio 自动生成视图,如 Listing 5所示。这一view 包含HTML表单,它包含与Movie类的每个属性相对应的字段。

Listing 5 – Views\Home\Create.aspx

<%@ Page Title=”” Language=”C#” MasterPageFile=”~/Views/Shared/Site.Master” Inherits=”System.Web.Mvc.ViewPage<MovieApp.Models.Movie>” %>

<asp:Content ID=”Content1″ ContentPlaceHolderID=”TitleContent” runat=”server”>
Create
</asp:Content>

<asp:Content ID=”Content2″ ContentPlaceHolderID=”MainContent” runat=”server”>

<h2>Create</h2>

<% using (Html.BeginForm()) {%>
<%: Html.ValidationSummary(true) %>

<fieldset>
<legend>Fields</legend>

<div class=”editor-label”>
<%: Html.LabelFor(model => model.Id) %>
</div>
<div class=”editor-field”>
<%: Html.TextBoxFor(model => model.Id) %>
<%: Html.ValidationMessageFor(model => model.Id) %>
</div>

<div class=”editor-label”>
<%: Html.LabelFor(model => model.Title) %>
</div>
<div class=”editor-field”>
<%: Html.TextBoxFor(model => model.Title) %>
<%: Html.ValidationMessageFor(model => model.Title) %>
</div>

<div class=”editor-label”>
<%: Html.LabelFor(model => model.Director) %>
</div>
<div class=”editor-field”>
<%: Html.TextBoxFor(model => model.Director) %>
<%: Html.ValidationMessageFor(model => model.Director) %>
</div>

<div class=”editor-label”>
<%: Html.LabelFor(model => model.DateReleased) %>
</div>
<div class=”editor-field”>
<%: Html.TextBoxFor(model => model.DateReleased) %>
<%: Html.ValidationMessageFor(model => model.DateReleased) %>
</div>

<p>
<input type=”submit” value=”Create” />
</p>
</fieldset>

<% } %>

<div>
<%: Html.ActionLink(“Back to List”, “Index”) %>
</div>

</asp:Content>

在你创建 Create 视图后,你可以添加新的Movie 记录到数据库。按下F5键运行你的应用程序和点击Create New 的链接,你将看到如图13所示的表格。如果你完成并提交表单、一个新movie数据库记录诞生了。

注意,你自动获得表单验证。如果你忽略输入movie的发行日期,或者你输入一个无效的发布日期,那么这个表单被重新显示,并且发布日期字段将高亮显示。
编辑现有的数据库记录

在之前的部分,我们讨论了如何列举和创造新的数据库记录。在这最后一节中,我们将讨论如何修改现有的数据库记录。

首先,我们需要生成编辑表单。 因为Visual Studio将为我们自动生成编辑表单,所以这一步很容易。在Visual Studio代码编辑器中,打开HomeController.cs类 ,遵循以下步骤:

1。在代码编辑窗口,右键单击 Edit()方法,选择菜单选项“添加视图”。
2。确认勾选“创建强类型视图”。
3。从“视图数据类”下拉列表中,选择值MovieApp.Models.Movie。
4。从“视图内容”下拉列表中,选择值  Edit。
5。点击“添加”按钮来创造新的view(见图3)。

完成这些步骤,将添加一个Edit.aspx的视图到Views\Home文件夹中。这一视图包含用来编辑一个movie记录的HTML表单。Edit view包含一个相应于movie Id属性的HTML表单字段。因为你不想让人们编辑这个Id属性的值,你应该移除这个表单字段。

最后,我们还需要修改Home controller,使它支持编辑数据库记录。最新的HomeController类如Listing 6所示。

Listing 6 – Controllers\HomeController.cs (Edit methods)

//
// GET: /Home/Edit/5

public ActionResult Edit(int id)
{
//return View();
var movieToEdit = (from m in _db.Movies

where m.Id == id

select m).First();

return View(movieToEdit);
}
[AcceptVerbs(HttpVerbs.Post)]

public ActionResult Edit(Movie movieToEdit)
{

var originalMovie = (from m in _db.Movies

where m.Id == movieToEdit.Id

select m).First();

if (!ModelState.IsValid)

return View(originalMovie);

_db.ApplyCurrentValues<Movie>(originalMovie.EntityKey.EntitySetName, movieToEdit);
//_db.ApplyPropertyChanges(originalMovie.EntityKey.EntitySetName, movieToEdit);

_db.SaveChanges();

return RedirectToAction(“Index”);

}

在 Listing 6,我已经为2个重载的Edit()方法增添了更多的逻辑。第一个Edit()方法将返回相对应的Id传递参数的方法的movie数据库记录。第二个重载方法执行数据库中记录的更新。

注意,你必须检索到原来的movie,然后调用ApplyCurrentValues<Movie>、更新现有的在数据库中的movie。

总结
这个教程的目的就是让你初步了解如何创建一个ASP.NET MVC应用程序。我希望你们发现,创建一个 ASP.NET MVC web 应用程序与创建ASP 或者 ASP.NET应用程序是非常相似的。

在这一课中,我们只是解释ASP.NET MVC 框架的最基本的特征。在后续的教程中,我们将深入更多的主题,如controllers, controller actions, views, view data和HTML helpers。

[转载]11个非常棒的CSS3实现的图片画廊

mikel阅读(912)

[转载]11个非常棒的CSS3实现的图片画廊 – 梦想天空 – 博客园.

CSS3给WEB开发带来了革命性的影响,以前很多需要JavaScript实现的复杂效果,现在使用简单的CSS3就能实现。下面这些绚丽的图片画廊效 果就是用CSS3实现的。还有件非常有趣的事就是很多人都在使用宝丽来效果。(提示:点击图片即可浏览Demo,为了能查看完整效果,请使用 Safari、Chrome、Opera浏览器浏览)

Polaroid from Tutorialzine

来自Tutorialzine得宝丽来效果,CSS3实现的旋转,图片可拖动,还有Drop To Share功能。

(更多…)

[转载]ASP.NET实现RSS订阅(Rss Toolkit 1.0)

mikel阅读(1080)

[转载]ASP.NET实现RSS订阅(Rss Toolkit 1.0) – tryandtry.cn – 博客园.

RSS具有实现成本低、推广速度快的优点,已成为很多报纸媒介电子网站中的一项重要推广技术。本节将介绍如何在网站中实现RSS功能,此功能主要包括两部分:订阅功能和提供阅读器工具功能。今天讲讲订阅功能的实现技术。
1 使用Microsoft提供的RSS工具包
为了让用户可以在ASP.NET 2.0中方便地使用RSS技术,Microsoft提供了一个RSS工具包,使用户可以简单地实现RSS的订阅和阅读功能。
这个工具包提供了“RssDataSource”和“RssHyperLink”两个控件,开发人员通过对两个控件的拖曳,就可以轻松实现站点的RSS功能。
声 明 本工具全名为“RssToolkit-1-0-0-1”,支持C#语言。读者可从Microsoft站点下载到最新版本Rss Toolkit 2.0,但此版本对于由后台实现复杂的RSS阅读效果有点困难,而RssToolkit 1.0又难以找到,如果你们需要的话点击此处留言,我到时发给你们。

下面将介绍如何把工具包添加到VS 2005的工具箱中。
(1)打开VS 2005,新建一个网站“WebRSS”。
(2)打开“Default.aspx”页面,切换到设计视图,此时工具箱为可用状态。
(3)右击工具箱中的“常规”选项卡,在弹出的菜单中,单击“选择项”菜单命令,弹出“选择工具箱项”对话框,如图1所示。

图1 选择“工具箱”对话框

(4)单击“浏览”按钮,打开文件搜索对话框,如图2所示。

图2 文件搜索对话框

(5)在“查找范围”下拉框中,找到工具包所在的文件夹下的“bin”文件夹,并选中文件夹中的“RssToolkit.dll”文件。
(6)单击“打开”按钮,系统回到“选择工具箱项”对话框,此时系统自动选中dll文件中带的两个控件。
(7)单击“确定”按钮,此时在“常规”选项卡中,多了两个控件:“RssDataSource”和“RssHyperLink”。
至此,工具控件已经加载完毕,可以在VS 2005中使用Microsoft提供的RSS工具包了。
1.1 一个简单的RSS阅读器
本节将使用ASP.NET 2.0提供的数据控件,通过RSS工具箱中的“RssDataSource”数据源控件,实现一个只有一列的网格频道列表,并通过导航的方式显示频道的内容。具体步骤如下。
(1)切换到设计视图,将一个数据控件“DataList”控件拖曳到界面中。
(2)再将一个数据源控件“RssDataSource”控件拖曳到界面中。
(3)在“RssDataSource”控件的任务列表中,只有一项“配置数据源”,单击此菜单命令,弹出地址输入对话框,如图3所示。

图3 输入RSS地址对话框

(4)在地址文本框内,输入“http://www.tryandtry.cn/index.xml”,此处提供一个标准的RSS文件,并提供多个文章项。
(5)单击“OK”按钮,返回到设计视图。
(6)编辑数据控件“DataList”的绑定项,具体设置如代码清单1-1所示。注意此处已经通过属性“DataSourceID”,将“DataList”控件的数据源绑定到“RssDataSource”控件上。
代码清单1-1 DataList控件的数据源绑定设置
<asp:DataList ID=”DataList1″ runat=”server” DataSourceID=”RssDataSource1″>
<ItemTemplate>
title:
<asp:Label ID=”titleLabel” runat=”server” Text='<%# Eval(“title”) %>’ />
<br />
link:
<asp:Label ID=”linkLabel” runat=”server” Text='<%# Eval(“link”) %>’ />
<br />
description:
<asp:Label ID=”descriptionLabel” runat=”server”
Text='<%# Eval(“description”) %>’ />
<br />
pubDate:
<asp:Label ID=”pubDateLabel” runat=”server” Text='<%# Eval(“pubDate”) %>’ />
<br />
<br />
</ItemTemplate>
</asp:DataList>
//以下是RSS控件的代码
<cc1:RssDataSource ID=”RssDataSource1″ runat=”server”
Url=”http://www.tryandtry.cn/index.xml“>
</cc1:RssDataSource>
运行效果图:

图4 运行效果图(在此没对代码进行美化,大家学习时就改改)

(7)此时RSS的读取地址和数据控件的绑定内容都已经设置完毕。按“Ctrl+S”键保存页面的设计。
(8)将此页设计为起始页,按F5键运行程序,测试能否正确显示订阅的RSS新闻列表,运行结果如图4所示。
1.2 一个复杂的RSS阅读器
上一小节主要讲解了一个简单的阅读器的制作过程,本节将通过一个复杂的数据控件“GridView”,实现一个频道列表网格,其中列出频道的主题、链接和描述等信息,并采用数据源后绑定的技术为“GridView”控件配置数据源。具体实现步骤如下。
(1)在网站根目录下,添加一个Web窗体“RSSChanel”。
(2)切换到设计视图,将一个“GridView”控件拖曳到界面中,并设计其样式,具体样式如代码清单1-2所示。因为采用数据源后绑定的技术,此处不需为“GridView”控件配置数据源。
代码清单1-2 GridView的样式配置源HTML代码
<asp:GridView ID=”GridView1″ runat=”server” CellPadding=”4″ ForeColor=”#333333″
GridLines=”None”>
<FooterStyle BackColor=”#5D7B9D” Font-Bold=”True” ForeColor=”White” />
<RowStyle BackColor=”#F7F6F3″ ForeColor=”#333333″ />
<PagerStyle BackColor=”#284775″ ForeColor=”White” HorizontalAlign=”Center” />
<SelectedRowStyle BackColor=”#E2DED6″ Font-Bold=”True” ForeColor=”#333333″ />
<HeaderStyle BackColor=”#5D7B9D” Font-Bold=”True” ForeColor=”White” />
<EditRowStyle BackColor=”#999999″ />
<AlternatingRowStyle BackColor=”White” ForeColor=”#284775″ />
</asp:GridView>
(3)按F7键进入“RSSChanel”页面的代码界面。
(4)必须先添加对RSS工具所在的命名空间的引用,语法是:“Using RssToolkit;”。
(5)在“Page_Load”事件中,调用RSS工具的方法,实现:GridView,控件的数据源绑定,具体实现代码如清单1-3所示。
代码清单1-3 GridView的数据源后绑定代码
using RssToolkit;
public partial class RSSChanel : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
//创建一个频道
GenericRssChannel c = GenericRssChannel.LoadChannel(“http://www.tryandtry.cn/index.xml“);
//为GridView绑定数据源
//数据源来自频道中的所有项目
GridView1.DataSource = c.SelectItems();
GridView1.DataBind();
}
}
(6)全部完成后,按“Ctrl+S”键保存所做的设计。
(7)将此页设置为起始页,按F5键运行程序,测试网格绑定的频道列表是否正常导航,最终运行界面如图5所示。

图5 复杂阅读器运行界面

[转载]一次进销存软件架构的实践2——业务外观层设计

mikel阅读(999)

[转载]一次进销存软件架构的实践2——业务外观层设计 – Rick Carter – 博客园.

1.结构

根据经验可以发现一个界面总是一块一块的,每一块里都是一些基本控件(按钮、文本框或者日期控件等)或者是一个网格控件和树形控件等,如果每块 称为区域,里面的成为项,这样我们可以把界面抽象出两个基类:区域和项,从区域派生出的其他区域分别用来创建编辑区域、网格区域和树形区域,编辑区域中的 项由项这个类中的类型属性通过分支语句去创建。

然后就是各种类型的窗体包含的区域不同,那就再加一个外观的类,它有个属性存放所有的区域,从外观派生出的类定义各种可能的区域。而各区域的位置等信息是由窗体去做的。

这些类还有其他的职责,从外观派生出的类负责各区域的交互等,区域负责数据绑定、固定的事件、数据初始化等,项也有数据绑定的职责,外观类的职责就是多很多了,主要一个职责是运行机制。

事实上我不是一开始就这样思考的,我是希望各种控件等都能够用统一的方式创建、绑定、验证和权限,所以才想到有基类抽象他们,才有了项,但单有项还不能完成一个复杂的界面,所以一步一步的思考就成上面描述的结构了。

2.运行机制

这里简单列下运行时候要做的事。

1.预初始化

一些初始值的设置和合法性验证已决定是否继续等等必须放到窗体打开前的工作。

2.加载数据

通过外观类中的业务对象所实现的接口方法加载数据存储到外观类的dataset类型的数据属性中。

3.初始化权限

设置权限对象中一些与数据库中的数据有关的属性。

4.创建外观

这个时候窗体中的各控件就创建了。

5.初始化验证

同初始化权限,我的验证和权限用的是同样的一些类,我将他们抽象成了相同的东西。参考浅谈MIS系统架构,这块有些复杂但我不准备说了,用到了一个MB.JsEvaluator.dll来完成动态条件表达式。

6.结束初始化

7.绑定数据

[转载]ASP.NET MVC之视图引擎

mikel阅读(1008)

[转载]ASP.NET MVC之视图引擎 – Creason’s Tech Blog – 博客园.

最近微软发布了另外一个在ASP.NET MVC上应用的视图引擎Razor。通过前面一系列的探讨,我想大部分都了解了ASP.NET MVC整个的原理,包括TempData、ViewData、ModelBinding、Filter等,但是我们还不是太了解它的视图引擎的情况。 ASP.NET MVC的视图引擎具有非常好的扩展性,我们可以使用其它的视图引擎代替WebForm,或是同时使用多种试图引擎,这些都得益于ASP.NET MVC精美的设计,下面我们一起来观赏一下它的设计。

内容概览Top

ActionResult做了什么?Top

讲到视图引擎,不得不说ActionResult,因为在Controller中,我们看不到一点视图引擎的影子,唯一提供线索的只有ActionResult,所以我们必须先从AcionResult下手。

下面是ASP.NET MVC提供的所有的ActionResult类型的类图:

这其中用的最多的是ViewResult,ActionResult有一个抽象方法ExecuteResult,这个方法会向用户的请求中写入要输出的内容,比如Response.Write等操作。

最具代表性的ViewResultTop

ASP.NET MVC中,ViewResult用的最多,Controller有一个View方法,它来实例化一个ViewResult对象,并返回。下面是View方法:

protected internal virtual ViewResult View(string viewName, string masterName, object model) {
    if (model != null) {
        ViewData.Model = model;
    }

    return new ViewResult {
        ViewName = viewName,
        MasterName = masterName,
        ViewData = ViewData,
        TempData = TempData
    };
}

它实例化一个ViewResult对象,并对其ViewData、TempData赋值,以完成从Controller向页面的传值。

ViewResult继承自ViewResultBase,ViewResult有一个IView类型的View属性,IView接口只有一个方法:

public interface IView {
    void Render(ViewContext viewContext, TextWriter writer);
}

因此,我们推测IView用于输出内容给用户。ViewResult类的ExecuteResult方法证明了这一点:

public override void ExecuteResult(ControllerContext context) {
    if (context == null) {
        throw new ArgumentNullException("context");
    }
    if (String.IsNullOrEmpty(ViewName)) {
        ViewName = context.RouteData.GetRequiredString("action");
    }
    ViewEngineResult result = null;
    if (View == null) {
        result = FindView(context);
        View = result.View;
    }
    ViewContext viewContext = new ViewContext(context, View, ViewData, TempData);
    View.Render(viewContext, context.HttpContext.Response.Output);
    if (result != null) {
        result.ViewEngine.ReleaseView(context, View);
    }
}
    

ASP.NET MVC的视图引擎Top

从上一小节中,看到要想得到IView对象,必须先有ViewEngineResult对象,而ViewEngineResult对象是通过ViewResult类的FindView方法得到的:

protected override ViewEngineResult FindView(ControllerContext context) {
    ViewEngineResult result = ViewEngineCollection.FindView(context, ViewName, MasterName);
    if (result.View != null) {
        return result;
    }

    // we need to generate an exception containing all the locations we searched
    StringBuilder locationsText = new StringBuilder();
    foreach (string location in result.SearchedLocations) {
        locationsText.AppendLine();
        locationsText.Append(location);
    }
    throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture,
    MvcResources.Common_ViewNotFound, ViewName, locationsText));
}

从ViewResult类的FindView方法中,得知ViewEngineResult是通过 ViewEngineCollection的FindView得到的,而ViewEngineCollection正是ViewEngines的静态属性 Engines,Engines返回一个只有一个WebFormViewEngine类型实例的一个集合。所以,ViewEngineResult会是调 用WebFormViewEngine类的FindView方法返回的结果。如果ViewEngins的静态属性Engines有多个 ViewEngine提供,那么就依次遍历它们直到找到第一个不为空的ViewEngineResult为止。这样我们就可以在同一个MVC网站中使用多 种视图引擎了。

在WebFormViewEngine的FindView方法返回之前,它会为ViewEngineResult注 入一个IView类型的WebFormView实例,这样ViewEngineResult就作为一个中间人把IView类型给ViewResult了, 然后ViewResult借助IView的力量,把数据输出给用户。

它们的关系是: