[转载]Android 分享机顶盒项目的封装类《GridView》

mikel阅读(865)

[转载]Android 分享机顶盒项目的封装类《GridView》 – Terry_龙 – 博客园.

由于使用系统自带的GridView 不够灵活,不能允许拖拉控件,故自己结合LinearLayout 封装的一个GridView ,通过本篇文章的阅读你可以学会如何自定义控件,如何使用组合控件,如何为自己的组合控件添加数据源和如何为自定义控件添加属性。

首先,我们要实现的效果是这样的:

上面1 2也是一个封装控件,用来为应用程序分页,具体如何实现下篇文章会提到,本篇先讲GridView。如图,这是一个标准的800*480大小的屏幕,所以设置了一页GridView 显示的应用程序数据为 三行五列,不足五列则按需显示。

按照上面的图例需求,大致上可以把GridView 画成如下的方式:

思路如下:

默认将我们的组合控件设置为Orientation 是VERTICAL。  首先一行五个,那么一行以一个Orientation 为HORIZONTAL 的线性布局包起来。然后在一行结束后,将Orientation  的线性布局添加进组合控件里面来,不足五个则按需添加进来。

实现这一效果我们需要两个类,一个类用来表示GridView 的行,这里我们起名为TableRow,代码如下:

public class TableRow {
private TableCell[] cell;

public TableRow(TableCell[] cell) {
this.cell = cell;
}

public int getSize() {
return cell.length;
}

public TableCell getCellValue(int index) {
if (index >= getSize()) {
return null;
}
return cell[index];
}

public int getCellCount() {

return cell.length;

}

public int getLastCellCount() {
return lastRowCount;
}
}

另外一个类用来表示GridView 每行的列个,这里我们取名为TableCell,代码如下:

static public class TableCell {
private Object value;

public TableCell(Object value) {
this.value = value;
}

public Object getValue() {
return value;
}
}

并且我们还需要为GridView 设置一个外部可添加数据的方法,代码如下:

public void setAdapter(AppsAdapter appsAdapter) {
this.adapter = appsAdapter;
this.setOrientation(LinearLayout.VERTICAL);
bindView();
}

其中,AppsAdapter 是一个自定义的BaseAdapter ,代码很简单,这里就不列出来了。关键的还是要看bindView ,这个方法是本篇GridView 显示数据的核心方法,代码如下:

void bindView() {
removeAllViews();
int count = adapter.getCount();
TableCell[] cell
= null;
int j = 0;
LinearLayout layout;
tableRowsList
= new ArrayList<HashMap<String, Object>>();
for (int i = 0; i < count; i++) {
j
++;
final
int position = i;
if (j > getColumnCount() || i == 0) {
cell
= new TableCell[getColumnCount()];
}

final View view = adapter.getView(i, null, null);

view.setOnTouchListener(new OnTouchListener() {

@Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
unCheckPressed();
checkRowID
= 1;
checkColumnID
= 1;
if (onItemClickEvent != null) {

onItemClickEvent.onItemClick(position, event, view);
}
return false;
}
});

view.setOnLongClickListener(new OnLongClickListener() {

@Override
public boolean onLongClick(View v) {
if (onLongPress != null) {
onLongPress.onLongPress(v);
}
return true;
}
});
cell[j
1] = new TableCell(view);
if (j == getColumnCount()) {
lastRowCount
= j;
j
= 0;
HashMap
<String, Object> map = new HashMap<String, Object>();
TableRow tr
= new TableRow(cell);
map.put(
tableRow, tr);
tableRowsList.add(map);
layout
= new LinearLayout(getContext());
addLayout(layout, cell, tr.getSize(), tr);

} else if (i >= count 1 && j > 0) {
lastRowCount
= j;
HashMap
<String, Object> map = new HashMap<String, Object>();
TableRow tr
= new TableRow(cell);
map.put(
tableRow, tr);
tableRowsList.add(map);
layout
= new LinearLayout(getContext());
addLayout(layout, cell, j, tr);
}

}

}

getColumnCount()是一个属性,表示可以从xml或者从代码动态改变GridView 每列显示的个数,属性点的代码为如下:

public gridViewExt(Context context, AttributeSet attrs) {
super(context, attrs);
int resouceID = 1;
TypedArray typedArray
= context.obtainStyledAttributes(attrs,
R.styleable.GridViewExt);
int N = typedArray.getIndexCount();
for (int i = 0; i < N; i++) {
int attr = typedArray.getIndex(i);
switch (attr) {
case R.styleable.GridViewExt_ColumnCount:
resouceID
= typedArray.getInt(
R.styleable.GridViewExt_ColumnCount,
0);
setColumnCount(resouceID);
break;

}
}
typedArray.recycle();
}

当然,你必须在res 创建属性xml ,这里不多讲,可以去我博客看看如何为 View 添加属性

还有,还必须实现它的支持键盘的上下左右的焦点,下面的代码将会提供该功能,但还必须配合Activity 的操作,等下文再讲述。效果是这样的:

该 类的全部源码为:

GridViewExt

package com.yaomei.widget;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import Android.content.Context;
import Android.content.Intent;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.yaomei.activity.adapter.AppsAdapter;
import com.yaomei.activity.info.R;

public class gridViewExt extends LinearLayout {
public List<HashMap<String, Object>> tableRowsList;
private List<HashMap<String, Object>> app = new ArrayList<HashMap<String, Object>>();
private AppsAdapter adapter;

onItemClickListener onItemClickEvent;
onLongPressExt onLongPress;
int checkRowID = 1; // 选中行的下标
int checkColumnID = 1; // 选中列的下标
int lastRowCount = 1; // 最后一行的总数
private int ColumnCount; // 每列的总数

public void setColumnCount(int count) {
this.ColumnCount = count;
}

public int getColumnCount() {
return ColumnCount;
}

public interface onItemClickListener {
public boolean onItemClick(int position, MotionEvent event, View view);
}

public interface onLongPressExt {
public boolean onLongPress(View view);
}

public gridViewExt(Context context) {
this(context, null);
// TODO Auto-generated constructor stub
}

public gridViewExt(Context context, AttributeSet attrs) {
super(context, attrs);
int resouceID = 1;
TypedArray typedArray
= context.obtainStyledAttributes(attrs,
R.styleable.GridViewExt);
int N = typedArray.getIndexCount();
for (int i = 0; i < N; i++) {
int attr = typedArray.getIndex(i);
switch (attr) {
case R.styleable.GridViewExt_ColumnCount:
resouceID
= typedArray.getInt(
R.styleable.GridViewExt_ColumnCount,
0);
setColumnCount(resouceID);
break;

}
}
typedArray.recycle();
}

public void setOnItemClickListener(onItemClickListener click) {
this.onItemClickEvent = click;
}

public void setOnLongPressListener(onLongPressExt longPress) {
this.onLongPress = longPress;
}

public void NotifyDataChange() {
removeAllViews();
}

void bindView() {
removeAllViews();
int count = adapter.getCount();
TableCell[] cell
= null;
int j = 0;
LinearLayout layout;
tableRowsList
= new ArrayList<HashMap<String, Object>>();
for (int i = 0; i < count; i++) {
j
++;
final
int position = i;
if (j > getColumnCount() || i == 0) {
cell
= new TableCell[getColumnCount()];
}

final View view = adapter.getView(i, null, null);

view.setOnTouchListener(new OnTouchListener() {

@Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
unCheckPressed();
checkRowID
= 1;
checkColumnID
= 1;
if (onItemClickEvent != null) {

onItemClickEvent.onItemClick(position, event, view);
}
return false;
}
});

view.setOnLongClickListener(new OnLongClickListener() {

@Override
public boolean onLongClick(View v) {
if (onLongPress != null) {
onLongPress.onLongPress(v);
}
return true;
}
});
cell[j
1] = new TableCell(view);
if (j == getColumnCount()) {
lastRowCount
= j;
j
= 0;
HashMap
<String, Object> map = new HashMap<String, Object>();
TableRow tr
= new TableRow(cell);
map.put(
tableRow, tr);
tableRowsList.add(map);
layout
= new LinearLayout(getContext());
addLayout(layout, cell, tr.getSize(), tr);

} else if (i >= count 1 && j > 0) {
lastRowCount
= j;
HashMap
<String, Object> map = new HashMap<String, Object>();
TableRow tr
= new TableRow(cell);
map.put(
tableRow, tr);
tableRowsList.add(map);
layout
= new LinearLayout(getContext());
addLayout(layout, cell, j, tr);
}

}

}

private void addLayout(LinearLayout layout, TableCell[] cell, int size,
TableRow tr) {

LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(130,
110);
layout.setGravity(Gravity.LEFT);

layout.setOrientation(LinearLayout.HORIZONTAL);
for (int k = 0; k < size; k++) {
View remoteView
= (View) tr.getCellValue(k).getValue();
layout.addView(remoteView, k,
params);
}
LinearLayout.LayoutParams firstParams
= new LinearLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
firstParams.leftMargin
= 60;
addView(layout, firstParams);
}

public void setAdapter(AppsAdapter appsAdapter) {
this.adapter = appsAdapter;
this.setOrientation(LinearLayout.VERTICAL);
bindView();
}

public void checkPressed(int tableRowId, int tableRowColumnId) {
ViewGroup view
= (ViewGroup) this.getChildAt(tableRowId);

checkColumnID = tableRowColumnId;
checkRowID
= tableRowId;
changeImageState(view.getChildAt(tableRowColumnId), app);

}

public void onClick(int tableRowId, int tableRowColumnId, Context context) {
LinearLayout view
= (LinearLayout) ((ViewGroup) this
.getChildAt(tableRowId)).getChildAt(tableRowColumnId);

TextView tv = (TextView) view.findViewById(R.id.folder);
final String[] name
= tv.getText().toString().split();
Intent intent
= null;
if (name[0].toString().equals(com.android.contacts)) {
if (name[1].toString().equals(
com.android.contacts.DialtactsActivity)) {
intent
= new Intent(Intent.ACTION_DIAL);
}
if (name[1].toString().equals(
com.android.contacts.DialtactsContactsEntryActivity)) {
intent
= new Intent(Intent.ACTION_CALL_BUTTON);
}
}
else {
intent
= getContext().getPackageManager()
.getLaunchIntentForPackage(name[
0].toString());
}
context.startActivity(intent);

}

/**
* 改变图片状态
*
* @param v
* @param list
*/
private void changeImageState(View v, List<HashMap<String, Object>> list) {
int size = list.size();
for (int i = 0; i < size; i++) {
View view
= (View) list.get(i).get(touch);
view.setPressed(
false);
list.remove(i);
}
v.setPressed(
true);
HashMap
<String, Object> map = new HashMap<String, Object>();
map.put(
touch, v);
list.add(map);

}

public void unCheckPressed() {
if (checkColumnID != 1 && checkRowID != 1) {
ViewGroup view
= (ViewGroup) this.getChildAt(checkRowID);
view.getChildAt(checkColumnID).setPressed(
false);

}
}

public class TableRow {
private TableCell[] cell;

public TableRow(TableCell[] cell) {
this.cell = cell;
}

public int getSize() {
return cell.length;
}

public TableCell getCellValue(int index) {
if (index >= getSize()) {
return null;
}
return cell[index];
}

public int getCellCount() {

return cell.length;

}

public int getLastCellCount() {
return lastRowCount;
}
}

static public class TableCell {
private Object value;

public TableCell(Object value) {
this.value = value;
}

public Object getValue() {
return value;
}
}

}

每行显示的LAYOUT文件:

<LinearLayout android:orientation=”vertical”
android:background
=”@drawable/lessbtn” android:gravity=”center”
android:layout_width
=”fill_parent” android:id=”@+id/grid_layout”
android:layout_height
=”fill_parent” xmlns:android=”http://schemas.android.com/apk/res/android”>

<ImageView android:id=”@+id/btn_appicon”
android:layout_width
=”55dip” android:layout_height=”55dip”></ImageView>
<TextView android:id=”@+id/tv_name” android:layout_width=”wrap_content”
android:textColor
=”#030303″ android:layout_height=”wrap_content”></TextView>
<TextView android:id=”@+id/folder” android:layout_width=”wrap_content”
android:visibility
=”invisible” android:layout_height=”wrap_content”></TextView>

</LinearLayout>

完成这一系列的编写后,你就可以在xml直接写或者在JAVA文件里面new 出来,但注意要设置它每列显示的个数。

下篇将讲述如何实现手势切屏,如何实现分页显示数据,如何实现封装分页控件。

[转载]让Python在Android系统上飞一会儿:第二节 第一个有实用价值的应用

mikel阅读(762)

[转载]让Python在Android系统上飞一会儿:第二节 第一个有实用价值的应用 – 铁骑世界 – 博客园.

本节目录

1.本节相关的python知识
2.图书价格查询器的功能分析
3.图书价格查询器的设计实现

1.python预备知识

单行注释使用#号,#以后的内容是注释,不会被解释器解释执行执行;
import语句用来导入模块,后面跟模块名;
python中的变量不需要声明类型,变量被赋值之后类型会自动指定,这也是动态语言的特性之一;

元组,python基本数据结构之一,使用这样的形式表示:元组1=(数据1,数据2,数据3)
元组一旦生成后就不能修改了
元组可以嵌套包括他自己在内的所有列表类型的数据集合,如:元组2=(元组1,数据4,数据5)
元组中数据的获取方法: 元组名[索引编号]

字典,python基本数据结构之一,使用这样的形式表示:字典1={键1:值1,键2:值2,键3:值3}
字典可以嵌套包括他自己在内的所有列表类型的数据集合
字典中数据的获取方法:字典名[键名] 或者 字典名[索引编号]

格式化字符串:字符串中的%s会被后面的对象替换掉,例如:
‘Hello,%s’ % ‘PuLee’
最后返回的结果是:
Hello,PuLee
注意两个字符串之间的那个%号不要漏掉了!

2.图书价格查询器的功能分析

第一步:调用条形码扫描程序,扫描书的条形码,然后从条形码中获得书籍的ISBN编号

第二步:构造查询书籍价格的Url地址,使用豆瓣的图书搜索功能

第三部:打开浏览器,传入构造好的Url地址,返回查找的结果

3.图书价格查询器的设计实现

实现代码如下:
#导入Android的API模块
import Android
#获得操作对象
droid = Android.Android()
#运行扫描程序,返回一个元组
code = droid.scanBarcode()
#从扫描程序返回的元组中取得isbn编号
isbn = code[1][‘extras’][‘SCAN_RESULT’]
#构造查询书籍的Url
url = ‘http://book.douban.com/subject_search?search_text=%s&cat=1001′ % isbn
#打开浏览器,传入构造好的Url,返回查找结果
droid.startActivity(‘android.intent.action.VIEW’,url)

最后的返回的查询结果:

本文参考了文章:http://www.mattcutts.com/blog/android-barcode-scanner/

[转载]ASP.NET MVC3.0 中Razor 学习

mikel阅读(1190)

[转载]MVC3.0 中Razor 学习 – RyanDing – 博客园.

随着MVC3.0RTM版本的发布,最近将公司的项目从MVC2.0升级到MVC3.0。同时打算在MVC3中全面使用Razor模板引擎。现将Razor学习拿出来和大家分享,如果存在不足的地方欢迎您指出。

其实在使用<%= %>在html中调用C#代码时,内心总在埋怨。这个写法非常麻烦。麻烦在哪呢?其实就是闭合。比如:

ASP.NET: <script src=”<%=Url.Content(“~/Scripts/JQuery-1.4.4.min.js”)%>”

Razor: <script src=”@Url.Content(“~/Scripts/JQuery-1.4.4.min.js”)”

非常明显,Razor在内部帮我们做了闭合“%>”。其实就是这个小小的闭合让我们可以在html内更加“流畅”的调用服务端代码。故Razor给开发带来了一定的便捷!下面介绍Razor的基本用法。

一、模板页


Razor出现后我们就可以选择不再使用ASP.NET master 模板页。取而代之的是cshtml razor的模板文件。用法个人认为还是和master模板页类似。但在mater模板页的原有功能上有了进一步扩展,更方便开发。比如只要在View文 件夹内加入_ViewStart.cshtml文件,我们就无需在每一个具体的View页面引入模板页。减少View页面内的重复代码。具体的可以建立一 个MVC3 Application 选择razor模板,VS会自动建立上述机制。这里值得提出的是@RenderSection方法。可以让我们在模板页预设一个区域,未来给继承该模板页 的View使用。具体请看以下操作:

在MVC3.0 shared文件夹下_Layout.cshtml这个模板文件内加入以下代码:

01 <!DOCTYPE html>
02 <html>
03 <head>
04 <title>@ViewBag.Title</title>
05 <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
06 <script src="@Url.Content("~/Scripts/jQuery-1.4.4.min.js")" type="text/JavaScript"></script>
07 @RenderSection("Head", required: true)
08 </head>
09 <body>
10 <div class="page">

以上代码第7行,预留出一个Head的section。 熟悉模板页的人,应该明白该处是预留是给未来具体的View页面自定义特定js/css使用的。这个View我们就用默认的Home底下的Index来举例。打开index.cshtml 写入以下代码

01 @{
02 ViewBag.Title = "Home Page";
03 }
04 <h2>@ViewBag.Message</h2>
05 @section Head{
06 <script type="text/JavaScript">
07 $(function () {
08 alert("hello jQuery");
09 });
10 </script>
11 }

该View已经集成了模板页,这里只是填充模板页内的Head section这时就可以加入我们的针对每个view页面的js或者CSS了。至此达到共性外的个性。

二、Razor语法:


文章开头就已经提到了,个人认为Razor语法的便捷在于razor自动帮助我们闭合C#或VB.NET在html的语法。请看以下代码:

已经给出注释了,仔细阅读并不难理解。您应该也能体会到如果将razor换成asp.net的<%= %>或者<%: %>写法,其实是很“痛苦”的。至于razor的其他用法官方网站已经写的很全面了,比如razor的已经为我们 HTML Encod防止XSS攻击、html中字符串中出现×××@×××.com这样的文本,Razor是可以自动识别成Email格式而不是Razor的关键字。


三、 Razor 语法智能提示:


该智能提示与VS内的一样,只需Ctrol + J 即可调出。具体的请看下图:

您是否和我一样也打算在Web开发中全面使用Razor呢? 本文的例子在这里下载

[转载]SQL Server 监控系列

mikel阅读(914)

[转载]SQL Server 监控系列 —— 一 – Sai~ – 博客园.

作为DBA,不仅仅是帮助开发人员写优秀的查询脚本、高效的数据存储架构。其实更多时候都是在运维,大部分工作时间都不算饱和的,可是为什么有些DBA如 此忙碌、狼狈不抗甚至等到客户或者乙方公司抱怨呢,那很多原因就是对SQL Server 的基础监控架构不熟悉,不够了解,不能自动化安排监控任务。

获取通知SQL Server为我们提供的诸如SQL Mail,Database Mail 邮件方式的信息发送方式,因此我们利用邮件来进行最基础的获取通知异常等情况。我在之前的文章提过Databasemail,大家可以做为参考

MSSQL数据库邮件系列一(环境搭建)

MSSQL数据库邮件系列二(SSMS和TSQL)

我提到了基本的邮件配置,但是也许我们的内网数据库是没有不能访问Internet的,如何发送到我们的监控邮箱呢。有朋友可能尝试会插入一个Mail 表,然后在另外一台能否访问Internet的内网机器读取该表来发送邮件,其实我们可以通过简单的SMTP中继来实现,我们知道的SMTP其实是个推协 议,一般是发送到提供商的STMP服务器,其实我们也能通过发送到自己的smtp服务器然后转发到指定DNS响应的SMTP服务器。

我测试是Windows Server 2008的机器,我们来安装SMTP服务器。首先打开

1.服务器管理器 –> 功能 –> 添加功能 –> SMTP 服务器。

2.安装成功以后,在管理工具 –> IIS (6.0) 管理器打开设置。

sqlmonitor_1

3.首先点击 域 –> 新建域 –> sqlmonitor_2(我新建了一个SMTP.QQ.COM的域,所以我要转发邮件到QQ邮箱)。

我们看到QQ提供的SMTP.QQ.COM使用的标准的25端口。所以打开WF.MSC 去添加25端口的出站规则,同时打开入站规则的25(让DB服务器能够中继到该SMTP服务器),不关闭选项卡。

4.在“出站安全”中->选择“基本身份验证”->添加你的邮箱登录帐号 –>(TSL加密根据你SMTP服务器的规则)来设置。

5.选中“SMTP Virtual Server #1” –> 右键属性 –> 切换到 “访问”选项卡 –>在“中继限制”中单击“中继” 添加你对应机器的访问列表。

6.最后一步,把你的DatabaseMail帐号设置成 匿名身份验证,SMTP服务器选择你的内网SMTP服务器地址,端口默认25,其他都不变动。

如果发送测试邮件通过说明没问题了,搞不定可以搜搜资料吧,或者直接提问。那么我也就解决了第一个问题“我们如何获取通知”,采用最基本的邮件方式。

详细的监控信息:数据库避免不了一些异常状态,比如错误的脚本导致的异常,空间不够,磁盘挂了,复制失败了等。这里我先提提SQL Server事件。这个意味着SQL Server发生特定错误产生的事件,每个事件都有对应的数据库、严重级别、错误号、错误文本。

打开SSMS->在SQL Server 代理 –>的警告中可以创建警告。一般来说我们关注大于等于13严重级别的事件。为乙方公司提供服务时快速的部署也很重要,因此我整理了一些脚本:

USE [msdb]
GO

/****** Object:  Alert [SQL_EVENT_13]    Script Date: 12/08/2010 14:44:53 ******/
EXEC msdb.dbo.sp_add_alert @name=N'SQL_EVENT_13',
        @message_id=0,
        @severity=13,
        @enabled=1,
        @delay_between_responses=1800,
        @include_event_description_in=1,
        @category_name=N'[Uncategorized]',
        @job_id=N'00000000-0000-0000-0000-000000000000'
GO

USE [msdb]
GO

/****** Object:  Alert [SQL_EVENT_17]    Script Date: 12/08/2010 14:45:03 ******/
EXEC msdb.dbo.sp_add_alert @name=N'SQL_EVENT_14',
        @message_id=0,
        @severity=14,
        @enabled=1,
        @delay_between_responses=1800,
        @include_event_description_in=1,
        @category_name=N'[Uncategorized]',
        @job_id=N'00000000-0000-0000-0000-000000000000'
GO

/****** Object:  Alert [SQL_EVENT_17]    Script Date: 12/08/2010 14:45:03 ******/
EXEC msdb.dbo.sp_add_alert @name=N'SQL_EVENT_15',
        @message_id=0,
        @severity=15,
        @enabled=1,
        @delay_between_responses=1800,
        @include_event_description_in=1,
        @category_name=N'[Uncategorized]',
        @job_id=N'00000000-0000-0000-0000-000000000000'
GO

/****** Object:  Alert [SQL_EVENT_17]    Script Date: 12/08/2010 14:45:03 ******/
EXEC msdb.dbo.sp_add_alert @name=N'SQL_EVENT_16',
        @message_id=0,
        @severity=16,
        @enabled=1,
        @delay_between_responses=1800,
        @include_event_description_in=1,
        @category_name=N'[Uncategorized]',
        @job_id=N'00000000-0000-0000-0000-000000000000'
GO

/****** Object:  Alert [SQL_EVENT_17]    Script Date: 12/08/2010 14:45:03 ******/
EXEC msdb.dbo.sp_add_alert @name=N'SQL_EVENT_17',
        @message_id=0,
        @severity=17,
        @enabled=1,
        @delay_between_responses=1800,
        @include_event_description_in=1,
        @category_name=N'[Uncategorized]',
        @job_id=N'00000000-0000-0000-0000-000000000000'
GO

/****** Object:  Alert [SQL_EVENT_17]    Script Date: 12/08/2010 14:45:03 ******/
EXEC msdb.dbo.sp_add_alert @name=N'SQL_EVENT_18',
        @message_id=0,
        @severity=18,
        @enabled=1,
        @delay_between_responses=1800,
        @include_event_description_in=1,
        @category_name=N'[Uncategorized]',
        @job_id=N'00000000-0000-0000-0000-000000000000'
GO

/****** Object:  Alert [SQL_EVENT_17]    Script Date: 12/08/2010 14:45:03 ******/
EXEC msdb.dbo.sp_add_alert @name=N'SQL_EVENT_19',
        @message_id=0,
        @severity=19,
        @enabled=1,
        @delay_between_responses=1800,
        @include_event_description_in=1,
        @category_name=N'[Uncategorized]',
        @job_id=N'00000000-0000-0000-0000-000000000000'
GO

/****** Object:  Alert [SQL_EVENT_17]    Script Date: 12/08/2010 14:45:03 ******/
EXEC msdb.dbo.sp_add_alert @name=N'SQL_EVENT_20',
        @message_id=0,
        @severity=20,
        @enabled=1,
        @delay_between_responses=1800,
        @include_event_description_in=1,
        @category_name=N'[Uncategorized]',
        @job_id=N'00000000-0000-0000-0000-000000000000'
GO

/****** Object:  Alert [SQL_EVENT_17]    Script Date: 12/08/2010 14:45:03 ******/
EXEC msdb.dbo.sp_add_alert @name=N'SQL_EVENT_21',
        @message_id=0,
        @severity=21,
        @enabled=1,
        @delay_between_responses=1800,
        @include_event_description_in=1,
        @category_name=N'[Uncategorized]',
        @job_id=N'00000000-0000-0000-0000-000000000000'
GO

/****** Object:  Alert [SQL_EVENT_17]    Script Date: 12/08/2010 14:45:03 ******/
EXEC msdb.dbo.sp_add_alert @name=N'SQL_EVENT_22',
        @message_id=0,
        @severity=22,
        @enabled=1,
        @delay_between_responses=1800,
        @include_event_description_in=1,
        @category_name=N'[Uncategorized]',
        @job_id=N'00000000-0000-0000-0000-000000000000'
GO

/****** Object:  Alert [SQL_EVENT_17]    Script Date: 12/08/2010 14:45:03 ******/
EXEC msdb.dbo.sp_add_alert @name=N'SQL_EVENT_23',
        @message_id=0,
        @severity=23,
        @enabled=1,
        @delay_between_responses=1800,
        @include_event_description_in=1,
        @category_name=N'[Uncategorized]',
        @job_id=N'00000000-0000-0000-0000-000000000000'
GO

/****** Object:  Alert [SQL_EVENT_17]    Script Date: 12/08/2010 14:45:03 ******/
EXEC msdb.dbo.sp_add_alert @name=N'SQL_EVENT_24',
        @message_id=0,
        @severity=24,
        @enabled=1,
        @delay_between_responses=1800,
        @include_event_description_in=1,
        @category_name=N'[Uncategorized]',
        @job_id=N'00000000-0000-0000-0000-000000000000'
GO

/****** Object:  Alert [SQL_EVENT_17]    Script Date: 12/08/2010 14:45:03 ******/
EXEC msdb.dbo.sp_add_alert @name=N'SQL_EVENT_25',
        @message_id=0,
        @severity=25,
        @enabled=1,
        @delay_between_responses=1800,
        @include_event_description_in=1,
        @category_name=N'[Uncategorized]',
        @job_id=N'00000000-0000-0000-0000-000000000000'
GO

.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas,”Courier New”,courier,monospace; background-color: rgb(255, 255, 255); }.csharpcode pre { margin: 0em; }.csharpcode .rem { color: rgb(0, 128, 0); }.csharpcode .kwrd { color: rgb(0, 0, 255); }.csharpcode .str { color: rgb(0, 96, 128); }.csharpcode .op { color: rgb(0, 0, 192); }.csharpcode .preproc { color: rgb(204, 102, 51); }.csharpcode .asp { background-color: rgb(255, 255, 0); }.csharpcode .html { color: rgb(128, 0, 0); }.csharpcode .attr { color: rgb(255, 0, 0); }.csharpcode .alt { background-color: rgb(244, 244, 244); width: 100%; margin: 0em; }.csharpcode .lnum { color: rgb(96, 96, 96); }

上面提供了 13-25严重级别的事件。有了事件,必然的,需要一个操作员或者说是监控人员来对获取事件来转发邮件,我们可以看到SQL Server 代理中 有 操作员的选项卡,可以创建操作员:

USE [msdb]
GO

/****** Object:  Operator [Terry Mao]    Script Date: 01/19/2011 11:37:34 ******/
EXEC msdb.dbo.sp_add_operator @name=N'Terry Mao',
        @enabled=1,
        @weekday_pager_start_time=90000,
        @weekday_pager_end_time=180000,
        @saturday_pager_start_time=90000,
        @saturday_pager_end_time=180000,
        @sunday_pager_start_time=90000,
        @sunday_pager_end_time=180000,
        @pager_days=0,
        @email_address=N'10000@qq.com',
        @category_name=N'[Uncategorized]'
GO

.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas,”Courier New”,courier,monospace; background-color: rgb(255, 255, 255); }.csharpcode pre { margin: 0em; }.csharpcode .rem { color: rgb(0, 128, 0); }.csharpcode .kwrd { color: rgb(0, 0, 255); }.csharpcode .str { color: rgb(0, 96, 128); }.csharpcode .op { color: rgb(0, 0, 192); }.csharpcode .preproc { color: rgb(204, 102, 51); }.csharpcode .asp { background-color: rgb(255, 255, 0); }.csharpcode .html { color: rgb(128, 0, 0); }.csharpcode .attr { color: rgb(255, 0, 0); }.csharpcode .alt { background-color: rgb(244, 244, 244); width: 100%; margin: 0em; }.csharpcode .lnum { color: rgb(96, 96, 96); }我添加了一个 “Terry Mao” 的操作人员,对应邮件地址为10000的邮件地址,然后我们可能需要为所有的事件添加订阅人员, 也就是Terry Mao。

在视图中,可以查询到所有创建的警报:

SELECT * FROM msdb.dbo.sysalerts;
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas,”Courier New”,courier,monospace; background-color: rgb(255, 255, 255); }.csharpcode pre { margin: 0em; }.csharpcode .rem { color: rgb(0, 128, 0); }.csharpcode .kwrd { color: rgb(0, 0, 255); }.csharpcode .str { color: rgb(0, 96, 128); }.csharpcode .op { color: rgb(0, 0, 192); }.csharpcode .preproc { color: rgb(204, 102, 51); }.csharpcode .asp { background-color: rgb(255, 255, 0); }.csharpcode .html { color: rgb(128, 0, 0); }.csharpcode .attr { color: rgb(255, 0, 0); }.csharpcode .alt { background-color: rgb(244, 244, 244); width: 100%; margin: 0em; }.csharpcode .lnum { color: rgb(96, 96, 96); }当然不可能一个去添加订阅事件,可以创建类似功能的sp:

CREATE PROC dbo.sp_add_all_notification
    @Operator sysname
AS
BEGIN
DECLARE @Name sysname,@OperatorID int;
SELECT @OperatorID = id FROM msdb.dbo.sysoperators WHERE name = @Operator;
IF @OperatorID IS NULL
    RETURN -1;
    
DECLARE Cur CURSOR FAST_FORWARD READ_ONLY LOCAL FOR SELECT [name] FROM
msdb.dbo.sysalerts alters WHERE NOT EXISTS
(SELECT 1 FROM msdb.dbo.sysnotifications notify
WHERE notify.operator_id = @OperatorID AND notify.alert_id = alters.id);
OPEN Cur;

FETCH NEXT FROM Cur INTO @Name;
WHILE @@FETCH_STATUS = 0
BEGIN
    EXEC msdb.dbo.sp_add_notification @alert_name = @Name,
@operator_name = @Operator,
@notification_method = 1;
    FETCH NEXT FROM Cur INTO @Name;
END

CLOSE Cur;
DEALLOCATE Cur;
RETURN 0;
END

.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas,”Courier New”,courier,monospace; background-color: rgb(255, 255, 255); }.csharpcode pre { margin: 0em; }.csharpcode .rem { color: rgb(0, 128, 0); }.csharpcode .kwrd { color: rgb(0, 0, 255); }.csharpcode .str { color: rgb(0, 96, 128); }.csharpcode .op { color: rgb(0, 0, 192); }.csharpcode .preproc { color: rgb(204, 102, 51); }.csharpcode .asp { background-color: rgb(255, 255, 0); }.csharpcode .html { color: rgb(128, 0, 0); }.csharpcode .attr { color: rgb(255, 0, 0); }.csharpcode .alt { background-color: rgb(244, 244, 244); width: 100%; margin: 0em; }.csharpcode .lnum { color: rgb(96, 96, 96); }这样就会把所有的事件全部给监控起来,其实我就解决了过滤的监控列表,但是我们可能会对运行中的SQL Server 比如长时间执行的语句,存储过程进行监控来调优。比如,我们给另外一家公司做DBA顾问,就立马需要获取有问题的查询,这个我会在接下来的文章详细说明。 其中包括Profile的监控,SQL Server WMI的监控等。

[转载]介绍一个基于ASP.NET MVC的框架Catharsis

mikel阅读(1050)

[转载]介绍一个基于ASP.NET MVC的框架Catharsis – 周金根 – 博客园.

Catharsis是一个基于ASP.NET MVC的一个开源框架,之前在codeproject上看到的。在我的2011生活看板中也说到今年准备给OpenExpressApp增加B/S支持,所以最近花了几天时间看了一下Catharsis,以下简单介绍一下。

Catharsis介绍

Web-application framework, multi-tier (5-tier) Architecture (SQL or XML is persitence, DAO as the only access point to get/store data -NHibernate 3.0, Facades as the only Business rule validation place, MVC pattern (Views on the RAZOR only) and UI (HTML, CSS and JQuery).

ASP.NET MVC 3.0 RC – Razor,
The Web-application framework gathering the best practices and design patterns.
Strongly OOP, multi-tier Architecture, NHibernate 3.0, XML, ADO.NET
VS 2010, .NET 4.0 (Contracts, Covariance, Named and Default parameters)

项目地址:http://catarsa.com

http://www.codeplex.com/Catharsis/

文档:http://www.codeproject.com/KB/applications/Catharsis_part3.aspx

主界面:

架构图

Solution结构

根据上面的架构图,从一个示例Solution可以看到各自对应的项目

通过向导生成实体对应的完整代码

结合VS,Catharsis提供了Recipe来生成项目代码文件,在生成实体时可以自动生成各个层的对应代码

Controller继承体系

以下是框架对实体控制器的一个继承体系,框架特意抽取了一个CodeList来存储具有Code、Name的简单列表的类,这个类可以使用smallint、tinyint来作为主键以减少数据库存储空间

  • CurrencyController:Currency为一个示例实体,这个为特定实体控制器
  • CodeListController:具有Code、Name的一个内置实体控制器
  • EntityController:通用的具有读写行为的控制器(添加、更新、删除)
  • ReadController:通用的具有读取功能行为的控制器(查询、列表、详细信息)
  • WebController:not only for entity, IMasterModel introduced, service operations (ObjectBinding())
  • Controller: ASP.NET MVC框架的控制器

一些不足

  • 运行比较慢
  • 界面不太美观
  • UI模板抽取不是很好
  • 没有什么太吸引我的地方

可借鉴的

  • 强OO、多层框架
  • 实体控制类的继承
  • ASP.NET MVC的使用
  • 多语言的支持

由于没有细看,很多具体实现还有待细看,毕竟我对B/S开发还有很多需要学习的,所以以上分享可能会有偏差

[转载]看一下基于ASP.NET MVC的开源社区项目Orchard

mikel阅读(1017)

[转载]看一下基于ASP.NET MVC的开源社区项目Orchard – 周金根 – 博客园.

昨天介绍了基于ASP.NET MVC的框架Catharsis,今天给大家介绍的是基于ASP.NET MVC的一个开源社区项目Orchard,本篇主要介绍一下Orchard是什么,如何下载安装以及安装过程中我遇到的几个问题和解决办法。

Orchard是一个免费和开源的社区交流项目,致力于在ASP.NET 平台开发应用程序和可重用性组件。它将创建用于ASP.Net应用和扩展的共享组件,以及修改这些组件以便使其应用于终端用户,脚本人员和开发者。我们也 寻求与现有的应用程序的作者建立伙伴关系,以帮助他们实现自己的目标。使用的开源协议是OSI认证的 New BSD license。

Orchard项目的计划目标是以下三方面:

  1. 独特的基于.Net, 能够吸引终端客户,脚本人员和开发人员的应用程序;
  2. 一个可复用的组件集合并能够简单建立这些应用;
  3. 一个强有力的社区去帮助定义这些应用和扩展。

在近期,Orchard 项目致力于发布基于.Net CMS 的程序,这些程序允许用户快速建立以内容驱动的站点,并且提供扩展框架能够允许开发人员和定制人员通过模块和主题增加额外的内容。你可以通过 Orchard Project Site(http://orchardproject.net) 去学习更多关于这个课题的内容。以下为项目网站首页:

下载安装

作为想学习这个社区网站如何设计的架构和开发人员来说,下载代码是必须的,所以我选择在http://orchard.codeplex.com/releases/view/50197下载1.0版本的源代码,然后发布到IIS上

还可以通过其他方式安装,可以参考Orchard 发布1.0版本和ASP.NET MVC 3 RTM

注意:如果你现在下载它推荐,当发布时会出现文件缺失的错误提示,所以你还是选择和我一样的方法吧

运行可能会遇到的问题

  1. 现象:提示没有安装ASP.Net
    原因:是在装完VS2010之后再安装系统的IIS组件的,所以IIS还未安装ASP.NET相关组件,所以发布后运行会出现这个错误
    解决方案:执行相应版本的aspnet_regiis.exe –i
  2. 现象:安装主题或模块报错

    原因:由于下载主题后需要拷贝文件,由于目录的安全性没有添加用户修改权限所以不能安装
    解决方案:给系统的Temp目录增加everyone用户修改权限后再次安装后正常

例如安装下面并应用这个主题时主界面如下图所示,看起来还比较酷吧:)

后面我将会继续介绍它的具体功能以及技术架构方面的内容。

[转载]高性能MMORPG通用服务端引擎设计之->基本概念篇二

mikel阅读(757)

[转载]高性能MMORPG通用服务端引擎设计之->基本概念篇二 – 懒人居 – Coding for fun – 博客园.

上回说道我们将服务器组的职责划分为了,前端服务器,场景服务器,登录服务器,数据服务器…etc.

如图:

Logic-Service   Logic-Service    DB-Service

|                     |                     |

———————————–

|

Scene Manager

|

————————————-

|                       |                      |

Front Server   Front Server     Login Server

|                      |

Client             Client

不过经过思考后发现这个结构有点问题。

问题何在呢?我们来好好分析一下游戏的逻辑后会发现,整个MMORPG的服务端逻辑,其实是对服务端事件的响应,这里有两种事件,一种是对自身属性 的改变(比如切换技能,向腰带放入药瓶之类的),一种是改变其他玩家属性,或者是需要通知其他玩家知道的自身属性改变(比如,攻击对方,自己回血,换装, 移动等),也就是前文中我们分析发生在场景中的事件,第二种事件远远超过第一种事件,而且大部分的业务逻辑也发生在这些事件中,所以这类事件的处理需要消 耗更多的CPU。这样就带来问题了,前端服务器的压力主要在IO,而场景服务器的压力主要在CPU,那么如果分开在不同的机器上部署,那么这两边服务器的 压力就不均衡了,前端服务器的CPU剩余很多,场景服务器的CPU又不够用。所以我决定将这两个部分再次合并起来,合成Logic服务,然后多个 Logic服务并行运行。

所有的游戏逻辑都在逻辑服务中运算,但是按照MMORPG的业务,所有的逻辑基本都是按照场景来分布的,所以这个时候我门又面临2难的选择题了。第 一种方案是,我们可以按照场景来组织逻辑,比如服务器A负责1,3,5,7场景,服务器B负责2,4,6场景,因为场景之间的人数不平均,有的场景人多 (比如某某城内,正在被大批人追杀的BOSS所在地),有的场景人少(比如运行一段时间后的新手村),而且游戏中的热点场景是动态变化的,随着游戏进程的 发展会有变化。所以这个情况下我们需要一个场景管理服务,这个服务用于监控每个逻辑服务,将热点场景所在的服务里的其他场景迁移到空闲逻辑服务器。这个逻 辑需要客户端提供支持,要实现服务器的软切换。还有一种方式是将场景的逻辑随机分布到所有逻辑服务器上,场景间的联系通过消息来传递,由一个消息服务器来 为所有场景提供广播组来分发消息。这样就会多个消息服务器出来。这两个方案中第一个对单个玩家来说延迟最小,但是如果场景管理做得不好就会造成CPU资源 分布不均匀,还有就是场景容量受到单个进程处理能力极限的局限。第二种方案延迟肯定大过第一种,但是场景的容量不受单个进程计算能力的影响,扩展性更好一 点。

最后我决定用Python来实现这个想法,一,有丰富的基础框架可以选择,比如用高性能的Gevnet或者Eruasia来作为TCP Server的基础。二是Python本来就是动态的,所以不需要再嵌入另一个动态语言来适应多变的业务逻辑了。其三是Python是动态类型的,在实现 消息服务的时候更方便。本来打算用erlang的,不过暂时对OTP还不是很熟悉所以暂时作罢,不过如果采用第二种方式的话我可能会用Erlang来实现 消息服务器。

下一章直接进入实现阶段,并且无论如何我都会把这个玩意儿弄出来,如果没有公司愿意花钱让我弄,我就业余时间自己弄出来开源,哼哼

[转载]抢火车票利器:分享一个抓取火车票转让信息的小程序

mikel阅读(815)

[转载]抢火车票利器:分享一个抓取火车票转让信息的小程序 – guozili@163.com – 博客园.

代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.ComponentModel;
using System.Threading;
using System.Text.RegularExpressions;
using System.Diagnostics;

namespace HuoChePiao
{
class Program
{
private static HashSet<string> results;
private static WebClient wc;
private static List<Site> sites;
private static int index;
private static bool isFirstRound;

static void Main(string[] args)
{
sites
= new List<Site>();

sites.Add(new Site()
{
Name
= 火车票网,
Url
= http://www.huochepiao.com/City/SearchCheCi.asp?leixing=%D7%AA%C8%C3&zhuti=t189&psearch=%C7%F3%B9%BA%2F%D7%AA%C8%C3%BC%EC%CB%F7,
RegexPattern
= @”· <A href=(.*?) target=_blank>(.*?)</a>,
Encoding
= Encoding.Default
});

sites.Add(new Site()
{
Name
= 百姓网,
Url
= http://beijing.baixing.com/huochepiao/?%E8%BD%A6%E6%AC%A1=T189,
RegexPattern
= @”“” ><a href=””/(.*?)””>(.*?)</a></td>,
Encoding
= Encoding.UTF8,
Domain
= http://beijing.baixing.com/,
Keys
= new string[] { }
});

sites.Add(new Site()
{
Name
= 百姓网,
Url
= http://beijing.baixing.com/huochepiao/?%E8%BD%A6%E6%AC%A1=T5,
RegexPattern
= @”“” ><a href=””/(.*?)””>(.*?)</a></td>,
Encoding
= Encoding.UTF8,
Domain
= http://beijing.baixing.com/,
Keys
= new string[] { }
});

sites.Add(new Site()
{
Name
= 酷讯网,
Url
= http://huoche.kuxun.cn/zhuanrang-checi-beijing-T189.html?type=1,
RegexPattern
= @”<span class=””col_11 left””><a target=””_blank”” href=””(.*)””>(.*)</a>,
Encoding
= Encoding.UTF8
});

sites.Add(new Site()
{
Name
= 酷讯网,
Url
= http://huoche.kuxun.cn/zhuanrang-checi-beijing-T5.html?type=1,
RegexPattern
= @”<span class=””col_11 left””><a target=””_blank”” href=””(.*)””>(.*)</a>,
Encoding
= Encoding.UTF8
});

sites.Add(new Site()
{
Name
= 酷讯网,
Url
= http://huoche.kuxun.cn/zhuanrang-checi-beijing-k185.html?type=1,
RegexPattern
= @”<span class=””col_11 left””><a target=””_blank”” href=””(.*)””>(.*)</a>,
Encoding
= Encoding.UTF8
});

sites.Add(new Site()
{
Name
= 清华网,
Url
= http://www.newsmth.net/bbsbfind.php?q=1&board=Ticket&title=T189&title3=%C7%F3&dt=1,
RegexPattern
= @”<a href=””(bbscon.php.*)””>(.*)</a>,
Encoding
= Encoding.Default,
Domain
= http://www.newsmth.net/
});

sites.Add(new Site()
{
Name
= 清华网,
Url
= http://www.newsmth.net/bbsbfind.php?q=1&board=Ticket&title=K185&title3=%C7%F3&dt=1,
RegexPattern
= @”<a href=””(bbscon.php.*)””>(.*)</a>,
Encoding
= Encoding.Default,
Domain
= http://www.newsmth.net/
});

results = new HashSet<string>();

isFirstRound = true;

wc = new WebClient();
wc.Encoding
= sites[index].Encoding;

wc.DownloadStringCompleted += new DownloadStringCompletedEventHandler(wc_DownloadStringCompleted);
wc.DownloadStringAsync(
new Uri(sites[index].Url));

int order;
while (int.TryParse(Console.ReadLine(), out order))
{
OpenLink(results.ElementAt(order
1));
Console.ForegroundColor
= ConsoleColor.Green;
}
}

static void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
int i = 0;

MatchCollection mc = Regex.Matches(e.Result, sites[index].RegexPattern);
foreach (Match m in mc)
{
if (m.Success)
{
string result = sites[index].Domain + m.Groups[1].Value;
string content = m.Groups[2].Value;
if (!results.Contains(result))
{
bool isContainKey = true;
if (sites[index].Keys != null)
{
foreach (string key in sites[index].Keys)
{
if (!content.Contains(key))
{
isContainKey
= false;
break;
}
}
}

if (!isContainKey)
continue;

results.Add(result);

Console.ForegroundColor = isFirstRound ? ConsoleColor.Gray : ConsoleColor.White;

Console.WriteLine({0} <{1}>  {2}.  {3}, DateTime.Now.ToShortTimeString(), sites[index].Name, results.Count, m.Groups[2].Value);

if (!isFirstRound)
{
OpenLink(result);
}
}
}

if (i++ > sites[index].Numbers 2)
break;
}

Thread.Sleep(1000);

index = index + 1;
if (index == sites.Count)
{
index
= 0;

if (isFirstRound)
isFirstRound
= false;
}

wc.Encoding = sites[index].Encoding;
wc.DownloadStringAsync(
new Uri(sites[index].Url));
}

static void OpenLink(string url)
{
Process.Start(url,
_blank);
}
}

public class Site
{
//站点名称
public string Name { get; set; }
//站点的网址
public string Url { get; set; }
//正则表达式
public string RegexPattern { get; set; }
//编码
public Encoding Encoding { get; set; }
//网站名称
public string Domain { get; set; }
//包含关键字
public string[] Keys { get; set; }
//取前面多少条
public int Numbers { get; set; }

public Site()
{
this.Numbers = 3;
}
}
}

每年都用这个抢到票了,今天也不例外,分享给大家:

1. 里面的规则你可以自己添加,我已经写好了很多,你把网址里德车次改下就行了

2. 初始化会抓取最新的信息,但是不弹出网页,你可以在控制台输入id号,弹出对应id号的网址

3. 后面会自动循环捕获每个站点的新信息,并弹出网页

快就一个字,希望大家都能买到火车票,安心回家

[转载]在没有安装 ASP.NET MVC3 的服务器上运行 MVC3

mikel阅读(841)

[转载]在没有安装 ASP.NET MVC3 的服务器上运行 MVC3 – haogj – 博客园.

当在服务器上部署 ASP.NET MVC3 的应用的时候,可能会看到如下的错误信息:

这表示你的服务器上没有安装 ASP.NET MVC3。

解决这个问题的方法有两种:

第一,当然是在服务器上安装 ASP.NET MVC3 了。不过,如果你使用的是服务器的虚拟空间,或者租用的服务器,可能没有安装的条件,那就是用第二种方法吧。

第二,错误的原因很显然是缺少适当的程序集,在已经安装 ASP.NET MVC3 的情况下,这些程序集已经被安装到 GAC 中,在网站程序中使用了对这些程序集的引用,MVC3 涉及的程序集如下所示:

我们可以通过在 ASP.NET MVC3 应用的 bin 下部署这些程序集来解决这个问题。

在开发 MVC3 应用的项目中,应该已经引用了这些程序集,在解决方案管理器中,展开引用,选中这 6 个程序集,在属性窗口中,将复制到本地 ( Copy Local)  设置为真,这将会导致在部署应用的时候,这些程序集将会被复制到本地。

在发布项目的时候,这些程序集,包括在 GAC 中的程序集将会被一起发布,这样,你的 MVC3 就可以运行了。

此文中图片来自:

Deployment of ASP.Net MVC 3 RC 2 Application on a Shared Hosting Environment Without Begging The Hosting Company

Deploying ASP.NET MVC 3 web application to server where ASP.NET MVC 3 is not installed

[转载]ASP.NET MVC Ajax Helpers

mikel阅读(1021)

[转载]MVC Ajax Helpers – CELERY – 博客园.

在MVC中要实现Ajax有很多的方式,有微软自己的MicrosoftAjax,也可以用JQuery的AJax来实现,如果对其他的JavaScript框架熟悉,还可以采用其他的实现方案,比如说Prototype等等。

以下是微软自己的实现方案。

需要预先加载的JavaScript文件:

    <script src="@Url.Content("~/Scripts/MicrosoftAjax.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/MicrosoftMvcAjax.js")" type="text/javascript"></script>

在MVC中已经提供了下面几个现成的HTML Hepler:

  • Ajax.ActionLink()
  • Ajax.BeginForm()
  • Ajax.RouteLink()
  • Ajax.BeginRouteForm()

Ajax.ActionLink

使用ActionLink发送异步请求的方法:

View

<div id="myPnl" style="width: 300px; height: 30px; border: 1px dotted silver;">
</div>
@Ajax.ActionLink("Click Me", "GetTime", new AjaxOptions { UpdateTargetId = "myPnl" })

Controller

public ActionResult GetTime()
{
    return Content(DateTime.Now.ToString());
}

以上示例使用ActionLink超链接发送请求到GetTime,返回一个ContentResult,通过AjaxOptions中的UpdateTargetId属性指定了需要更新的页面元素。

AjaxOptions中还有其他可以指定的属性:

Confirm 等效于javascript中的return confirm(msg),在点击该链接时先提示需要确认的信息。
HttpMethod 指定使用Get或者是Post方式发送Http请求
InsertMode 指定使用哪一种方式在指定的UpdateTargetId元素更新数据,可以有三种方式: “InsertAfter”, “InsertBefore”, or “Replace” 。默认为:Replace
LoadingElementDuration Loading元素显示的时间
LoadingElementId 可以指定在Http请求期间显示的Loading元素
OnBegin 在Http请求之前执行的javascript方法
OnComplete 在Http请求结束时执行的方法
OnFailure 在Http请求失败时执行的方法
OnSuccess 在Http请求成功时执行的方法
UpdateTargetId Http请求更新的页面元素
Url Http请求的Url

关于AjaxOptions中各方法的使用方法,在之前关于ActionResult的介绍的文章中有相关的列子:

JsonResult

注意点

  • OnComplete和OnSuccess的区别:OnComplete是获取了Http请求时引发的,此时页面还没有进行更新,OnSuccess是在页面已经更新后引发的。
  • ActionLink中的actionName和AjaxOption中的Url的关系:两者分别产生的HTML如下,但是执行的结果相同,希望有高手能解释下这两者有无区别。

<a href=”/Home/GetTime” data-ajax-update=”#myPnl” data-ajax-mode=”replace” data-ajax=”true”>Click Me</a>
<a href=”/” data-ajax-url=”Home/GetTime” data-ajax-update=”#myPnl” data-ajax-mode=”replace” data-ajax=”true”>Click Me</a>

Ajax.BeginForm

该Html Hepler可以实现使用Ajax方式提交Form,在指定的页面元素中显示提交的结果。

View

@model MvcAjax.Models.UserModel
@{
    ViewBag.Title = "AjaxForm";
}

<div id="myPnl" style="width: 300px; height: 30px; border: 1px dotted silver;">
</div>

@using (Ajax.BeginForm("SaveUser", new AjaxOptions { UpdateTargetId = "myPnl" }))
{
    <table>
        <tr>
            <td>
                @Html.LabelFor(m => m.UserName)
            </td>
            <td>
                @Html.TextBoxFor(m => m.UserName)
            </td>
        </tr>
        <tr>
            <td>
                @Html.LabelFor(m => m.Email)
            </td>
            <td>
                @Html.TextBoxFor(m => m.Email)
            </td>
        </tr>
        <tr>
            <td>
                @Html.LabelFor(m => m.Desc)
            </td>
            <td>
                @Html.TextBoxFor(m => m.Desc)
            </td>
        </tr>
        <tr>
            <td colspan="2">
                <input type="submit" value="Submit" />
            </td>
        </tr>
    </table>
}

Model

using System.ComponentModel.DataAnnotations;

namespace MvcAjax.Models
{
    public class UserModel
    {
        [Display(Name = "Username")]
        public string UserName { get; set; }

        [Display(Name = "Email")]
        public string Email { get; set; }

        [Display(Name = "Description")]
        public string Desc { get; set; }
    }
}

Controller

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

[HttpPost]
public ActionResult SaveUser(UserModel userModel)
{
    //Save User Code Here
    //......

    return Content("Save Complete!");
}

以上示例代码实现了采用Ajax提交Form数据的大概方法,在Ajax.BeginForm中同样使用AjaxOptions来设置Ajax请求的参数,和Ajax.ActionLink中的使用方法相同。

其他:

介绍JavaScriptResult时曾经提到了该ActionResult在普通的请求中是直接当作文件Reponse出的,但是在Ajax请求中,便可以使用该Result,并且执行Result中的JavaScript。

比如将上面的Conntroller更改为以下代码:

[HttpPost]
public ActionResult SaveUser(UserModel userModel)
{
    //Save User Code Here
    //......

    //return Content("Save Complete!");
    return JavaScript("alert('Save Complete!');");
}

便可在执行改Ajax请求之后执行JavaScriptResult中的语句。