关于工厂、单体、适配器、策略、观察者没啥好说的, 代码中有说明
//DesignPattern.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DesignPattern
{
//################################单体模式########################################
//单体模式思路: 禁止外接任意调用 --> 1. 构造函数做成私有的, 且本类禁止继承(密封类)
// 本类又需要创建实例, 且只能有一份 --> 2. 类的静态成员(静态变量), 因此需要静态构造函数并在其中创建实例
// 需要对外界提供调用方法 --> 3. 静态属性或者静态方法为外界提供调用
public sealed class Singleton //用sealed封闭类, 防止用其子类创建实例
{
private DateTime _createtime;
private Singleton() //私有构造函数, 禁止外接调用
{
this._createtime = DateTime.Now;
}
private static readonly Singleton inner; //静态只读变量, 只能创建唯一的实例
static Singleton() //通过静态构造函数, 返回本类的实例
{
inner = new Singleton();
}
public static Singleton GetSingleton //提供静态属性供外接调用
{
get
{
return inner;
}
}
public static Singleton CreateSingleton() //也可以提供静态方法供外接调用
{
return inner;
}
public override string ToString() //重写ToString()方法, 返回
{
return "该自定义对象的HashCode为: <"+inner.GetHashCode().ToString()+"> , 创建时间为: <"+this._createtime.ToString()+"> , 当前时间为: < "+DateTime.Now.ToString()+"> !";
}
}
//################################工厂模式########################################
//工厂模式的核心思想: 运行时绑定, 在运行时才创建对象. 工厂模式3大组成: 工厂、产品、抽象产品.
//工厂模式思路: 通过工厂类创建不同类的实例 --> 1. 嵌套类, 且不同类需要有"共有的基类"或"实现相同接口"
// 工厂类通常做成单独的程序集 --> 2. 这里做成嵌套类了, 被嵌套类为internal
// 需要对外界提供可返回实例的方法 --> 3. 根据静态方法的参数(switch), 返回不同的实例
public class Factory
{
internal sealed class Laptop : Computer,IFunction
{
public Laptop(string type,string manufacturer,double price)
: base("笔记本", type,manufacturer,price)
{
}
public override string ListFunction()
{
return "我是笔记本, 价格贵, 携带方便! ";
}
}
internal class Desktop : Computer,IFunction
{
public Desktop(string type, string manufacturer, double price)
: base("台式机", type, manufacturer, price)
{
}
public override string ListFunction()
{
return "我是台式机, 性能强悍, 易升级! ";
}
}
internal sealed class NetBook : Computer,IFunction
{
public NetBook(string type, string manufacturer, double price)
: base("上网本", type, manufacturer, price)
{
}
public override string ListFunction()
{
return "我是上网本, 容易携带, 节能环保! ";
}
}
//静态方法为外界提供实例(抽象类做容器)
public static Computer getComputer(string name)
{
Computer result = null;
switch (name)
{
case "台式机":
result = new Desktop("随想T250", "联想", 5888.88);
break;
case "笔记本":
result = new Laptop("ThinkPad-T500", "IBM", 18888.0);
break;
case "上网本":
result = new NetBook("mini 9", "Dell", 3000.00);
break;
default:
//nothing to do here
break;
}
return result;
}
//静态方法为外界提供实例(接口做容器)
public static IFunction getFunction(string name)
{
IFunction result = null;
switch (name)
{
case "台式机":
result = (IFunction)new Desktop("随想T250", "联想", 5888.88);
break;
case "笔记本":
result = (IFunction)new Laptop("ThinkPad-T500", "IBM", 18888.0);
break;
case "上网本":
result = (IFunction)new NetBook("mini 9", "Dell", 3000.00);
break;
default:
//nothing to do here!
break;
}
return result;
}
//静态方法通过反射提供实例(需要配置文件), 由于是嵌套类, 反射有点问题, 如果是程序集肯定没问题
public static Computer getComputerByConfig()
{
string typestr = System.Configuration.ConfigurationManager.AppSettings["FactoryStrategy"];
if (typestr == string.Empty)
{
throw new TypeLoadException("配置文件加载错误! ");
}
System.Type type = System.Type.GetType(typestr);
if (type == null)
{
throw new TypeLoadException("未知类型! ");
}
return System.Activator.CreateInstance(type) as Computer;
}
}
public abstract class Computer //抽象类做容器
{
//字段
private string _name;
private string _type;
private string _manufacturer;
private double _price;
//构造函数
public Computer(string name, string type,string manufacturer,double price)
{
this._name = name;
this._type = type;
this._manufacturer = manufacturer;
this._price = price;
}
//属性
public string Name
{
get
{
return this._name;
}
}
public string Type
{
get
{
return this._type;
}
}
public string Manufacturer
{
get
{
return this._manufacturer;
}
}
public double Price
{
get
{
return this._price;
}
}
public override string ToString()
{
return "我是: < "+this.Name+" > , 型号为: < " + this.Type + " > , 制造商是: < " + this.Manufacturer + " > , 价格是: < " + this.Price.ToString() + " > !";
}
public abstract string ListFunction();
}
public interface IFunction //接口做容器
{
string ListFunction();
}
//################################适配器模式#######################################
//适配器模式思路: 通过接口的不同实现影响程序的执行效果(程序代码基本不做变化) --> 1. 定义接口(适配器模式注重的是功能), 及若干实现类.
public interface ICallAdapter
{
string MakeACall();
}
internal class Beeper : ICallAdapter
{
public string MakeACall()
{
return "通过传呼台将信息< 新婚快乐, 百年好合! > 送给了他";
}
}
internal class TelPhone : ICallAdapter
{
public string MakeACall()
{
return "通过电话祝福他 < 新婚快乐, 百年好合! >";
}
}
internal class CellPhone : ICallAdapter
{
public string MakeACall()
{
return "通过手机将亲手制作的视频-- < 新婚快乐, 百年好合! > 发送给了他";
}
}
//适配器模式的惯用法:
//简单适配器(如上): 在业务逻辑比较简单且详细设计规范的情况下, 可以使用上边的方式, 在需要更换实现时直接修改源代码.
//惯用适配器: 当我们在项目中需要更换某个功能模块的实现时, 新模块的方法名、参数名(方法签名)等均与旧模块不同, 此时可以通过引入专门的适配器来解决.
//惯用适配器处理方式: 1. 新建类库项目并定义接口, 接口中规定需要实现的功能.
// 2. 创建新的适配器类, 该类继承自新模块中的实现类, 并实现定义的接口. 在新类的方法中, 通过base.方法名()调用新模块中的功能.
// 这样, 程序编码时使用IInterface ii = new NewClass();语句, 并调用接口ii上的方法即可. 当再发生改变时, 我们只需要在适配器中继承新模块的实现类, 并修改base后的方法即可. 之后把编译后的.dll文件拷贝到项目中去, 就可使用,源程序不做任何修改.
internal class MakeCall : Beeper, ICallAdapter //CellPhone
{
#region ICallAdapter Members
string ICallAdapter.MakeACall()
{
return base.MakeACall();
}
#endregion
}
//################################策略模式#######################################
//策略模式思路: 获得某个抽象类或接口的实现, 通过策略类(工具类)直接返回处理完成的结果.
// 与通过反射获得对象实例的工厂模式的区别: 工厂返回对象实例, 而策略强调完成任务、显示结果
// 1. 创建抽象基类或接口, 并创建若干实现类.
// 2. 创建策略类(工具类): 策略类利用反射从配置文件中获取对象实例后, 再调用对象上的方法, 返回结果
public abstract class Vehicle
{
public abstract string GetVehicleName();
}
internal class BoardingCar : Vehicle
{
public override string GetVehicleName()
{
return "我是小轿车! ";
}
}
internal class MotorBicycle : Vehicle
{
public override string GetVehicleName()
{
return "我是摩托车! ";
}
}
internal class Bike : Vehicle
{
public override string GetVehicleName()
{
return "我是自行车! ";
}
}
//策略类(工具类), 用于返回处理结果, 用户不会看到连接字符串、new等操作
public class VehicleProvider
{
public static string OutputName()
{
string typestr = System.Configuration.ConfigurationManager.AppSettings["Strategy"];
if (typestr == string.Empty)
{
throw new TypeLoadException("配置文件错误! ");
}
System.Type type = System.Type.GetType(typestr);
if (type == null)
{
throw new TypeLoadException("获取类型失败! ");
}
//这里和通过反射获得对象的工厂的区别就是: 一个返回实例, 一个返回处理完成的结果
Vehicle v = System.Activator.CreateInstance(type) as Vehicle;
return v.GetVehicleName();
}
}
//策略类(工具类)的另一种写法(适合项目文件多、业务逻辑较复杂的情况)
public class VehicleStrategy
{
private Vehicle _strategy;
public void SetStrategy(Vehicle strategy) //设置策略
{
this._strategy = strategy;
}
public string ExecuteStrategy() //执行策略
{
return this._strategy.GetVehicleName();
}
}
//################################观察者模式#######################################
//观察者模式思路: 观察者(被动方)根据被观察着(主动方)的行为, 做出不同的响应, 已实现联动效果.
// 1. 抽象出观察者的共有行为, 即接收被观察者发送的消息; 抽象出被观察着的行为, 即提添加观察者和发送信息给观察者(对行为的抽象, 适合接口)
// 2. 定义若干观察者的类, 实现观察者接口, 定义被观察者类, 实现被观察接口
// 3. 通过被观察者行为的变化影响所有的观察者
public interface IObserver //观察者(被动方), 接收信息
{
void ReceiveInfo(object obj);
}
public interface IActive //被观察着(主动方), 添加观察者和发送信息给观察者
{
void SendInfo(object obj); //添加观察者
void RegObserver(IObserver io); //发送信息
}
public class Car : IObserver
{
public void ReceiveInfo(object obj)
{
if (obj.ToString() == "红灯")
{
Console.WriteLine("红灯停, 轿车踩刹车! ");
}
else if (obj.ToString() == "绿灯")
{
Console.WriteLine("绿灯行, 轿车踩油门! ");
}
else
{
Console.WriteLine("黄灯将变灯, 轿车减速! ");
}
}
}
public class Bicycle : IObserver
{
public void ReceiveInfo(object obj)
{
if (obj.ToString() == "红灯")
{
Console.WriteLine("红灯停, 自行车下车! ");
}
else if (obj.ToString() == "绿灯")
{
Console.WriteLine("绿灯行, 自行车上车! ");
}
else
{
Console.WriteLine("黄灯将变灯, 自行车减速! ");
}
}
}
public class People : IObserver
{
public void ReceiveInfo(object obj)
{
if (obj.ToString() == "红灯")
{
Console.WriteLine("红灯停, 人站住! ");
}
else if (obj.ToString() == "绿灯")
{
Console.WriteLine("绿灯行, 人行走! ");
}
else
{
Console.WriteLine("黄灯将变灯, 人观察! ");
}
}
}
public class TrafficLight : IActive
{
//内部需要有个集合记录所有观察者
List<IObserver> list = new List<IObserver>();
public void SendInfo(object obj)
{
foreach (IObserver io in list)
{
io.ReceiveInfo(obj);
}
}
public void RegObserver(IObserver io)
{
list.Add(io);
}
}
//观察者模式2(抽象类实现):猫大叫, 主人醒, 老鼠跑
public abstract class Passive //观察者
{
public abstract void Act();
}
public abstract class Active //被观察者
{
public abstract void AddList(Passive pa);
public abstract void Shout();
}
public class Cat : Active
{
//通知列表
List<Passive> list = new List<Passive>();
public override void AddList(Passive pa)
{
list.Add(pa);
}
public override void Shout()
{
Console.WriteLine("猫大叫! ");
foreach (Passive p in list)
{
p.Act();
}
}
}
public class Mouse : Passive
{
public Mouse(string name)
{
this._name = name;
}
private string _name;
public string Name
{
get
{
return this._name;
}
set
{
this._name = value;
}
}
public override void Act()
{
Console.WriteLine(string.Format("老鼠 < {0} > 四下逃窜! ",this.Name));
}
}
public class Man : Passive
{
public override void Act()
{
Console.WriteLine(string.Format("主人惊醒! "));
}
}
}
//Progarm.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace DesignPattern
{
class Program
{
static System.Timers.Timer timer;
static string lightcolor = "红灯";
static TrafficLight tl;
static void Main(string[] args)
{
Console.WriteLine("------------单体模式(Singleton)-------------");
//Singleton s1 = new Singleton(); //无法直接创建Singleton的实例
Singleton s2 = Singleton.GetSingleton;
Console.WriteLine(s2.ToString());
Thread.Sleep(3000);
Singleton s3 = Singleton.GetSingleton;
Console.WriteLine(s3.ToString());
Thread.Sleep(3000);
Singleton s4 = Singleton.CreateSingleton();
Console.WriteLine(s4.ToString());
Console.WriteLine("\n------------工厂模式(Factory)-------------");
//基类容器
Computer c1 = Factory.getComputer("笔记本");
Console.WriteLine(c1.ToString());
Computer c2 = Factory.getComputer("上网本");
Console.WriteLine(c2.ToString());
//配置文件获取对象实例
//Computer c3 = Factory.getComputerByConfig();
//Console.WriteLine(c3.ToString());
//使用接口容器
IFunction i1 = Factory.getFunction("台式机");
Console.WriteLine(i1.ListFunction());
IFunction i2 = Factory.getFunction("上网本");
Console.WriteLine(i2.ListFunction());
Console.WriteLine("\n------------适配器模式(Adapter)-------------");
ICallAdapter ica = null; //使用接口盛放不同实现
ica = new TelPhone();
Console.WriteLine(NoticeInfo("同事结婚", "家里", ica));
ica = new CellPhone();
Console.WriteLine(NoticeInfo("好朋友结婚", "厕所", ica));
ica = new Beeper();
Console.WriteLine(NoticeInfo("爷爷再婚", "办公室", ica));
Console.WriteLine("\n------------惯用的适配器模式-------------");
ICallAdapter ica2 = new MakeCall();
Console.WriteLine(NoticeInfo("同事结婚", "家里", ica2));
Console.WriteLine("\n----------抽象类实现观察者模式1(Observer)-----------");
Cat cat = new Cat();
Mouse m1 = new Mouse("Jerry");
Mouse m2 = new Mouse("MickeyMouse");
Man man = new Man();
cat.AddList(m1);
cat.AddList(m2);
cat.AddList(man);
cat.Shout();
Console.WriteLine("\n------------接口观察者模式2(Observer)-------------");
tl = new TrafficLight();
Car car1 = new Car();
Bicycle bike1 = new Bicycle();
People people1 = new People();
tl.RegObserver(car1);
tl.RegObserver(bike1);
tl.RegObserver(people1);
//tl.SendInfo("红灯"); //测试
//tl.SendInfo("绿灯"); //测试
timer = new System.Timers.Timer();
timer.Interval = 1000 * 10; //推荐写法
timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
timer.Start();
Console.WriteLine("\n------------策略模式(Strategy)-------------");
Console.WriteLine(DesignPattern.VehicleProvider.OutputName()); //通过反射从配置文件获得对象信息
Console.WriteLine("\n------------策略模式另一种写法-------------"); //添加新策略时, 可以不修改源代码
System.Reflection.Assembly asm = System.Reflection.Assembly.LoadFrom(System.Configuration.ConfigurationManager.AppSettings["AssemblyPath"]);
Vehicle vehicle = asm.CreateInstance(System.Configuration.ConfigurationManager.AppSettings["ClassName"]) as Vehicle; //Vehicle为抽象类
VehicleStrategy vs = new VehicleStrategy(); //策略管类类
vs.SetStrategy(vehicle); //设置策略
Console.WriteLine(vs.ExecuteStrategy()); //执行策略, 添加新策略时只要配置好app文件中程序集位置和类名即可
Console.ReadLine(); //挂起程序
}
static void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
timer.Stop();
Console.WriteLine("\n-----------观察者模式2的回调结果--------------\n");
if (lightcolor == "红灯")
{
lightcolor = "绿灯";
}
else if (lightcolor == "绿灯")
{
lightcolor = "红灯";
}
tl.SendInfo(lightcolor);
Console.Write(Environment.NewLine);
timer.Start();
}
static string NoticeInfo(string content,string place, ICallAdapter mode) //适配器模式中的主要代码部分
{
return "< "+content+" > , 小明正在 < "+place+" > , 于是用 < "+mode.MakeACall()+" > !";
}
}
}
//App.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<!--<add key="FactoryStrategy" value="DesignPattern.Factory.Desktop,DesignPattern"/>-->
<add key="Strategy" value="DesignPattern.Bike,DesignPattern"/>
<!--可选MoterBicycle,car-->
<!--策略模式配置文件-->
<add key="ClassName" value="DesignPattern.MotorBicycle"/>
<add key="AssemblyPath" value="D:\重要未完成\DesignPattern\DesignPattern\bin\Debug\DesignPattern.exe"/>
</appSettings>
</configuration>
关于MVC设计模式的控制台Demo
//Model/Model.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
namespace MVCModel
{
//MVC模式的思想: 将界面设计和功能设计分开, 且同时进行设计, 最后通过Controller综合工作成果. 程序运行时, 按View-Controller-Model的流程执行
//功能开发人员可以向Controller提交dll文件, 也可以将dll注册到本机的全局程序集缓存(GAC)中(c:\windows\assembly).
//添加到GAC中的方法:
// 1. 添加完整的文档注释, 类型及成员均需添加且不可遗漏(类: 描述... ; 方法: 根据...; 属性: 获取或设置... ; 参数: System.xx类型, 表示...)
//
// 2. 添加完整程序集信息(通过创建空类库项目, 获得AssemblyInfo文件并修改)
// 主版本号: 软件版本重大变化, 如: 单机版到网络版
// 次要版本号: 软件功能变化, 如: 添加辅助挂机功能
// 内部版本号: 如: beta,final, 或同时做出几个不同方案, 最终选一个
// 修订号: 修改bug的次数
//
// 3. 通过类库中的强名称工具获得签名密钥(需在环境变量的Path中, 添加VS2008的SDK目录c:\program files\Microsoft SDKs\Windows\v6.0A\bin)
// cmd中生成强名称(注意大小写): sn -k strongname.snk 查看强名称: sn -T xxx.dll
// 备注: VS2005的SDK目录为c:\program files\Microsoft Visual Studio 8\SDK\v2.0\Bin
//
// 4. 将有完整文档注释的cs文件、AssemblyInfo文件及强名称文件编译成一个dll文件和XML文档
// cmd中键入命令: csc /target:library /doc:xxx.xml /keyfile:strongname.snk /out:xxx.dll AssemblyInfo.cs aaa.cs bbb.cs
//
// 5. 将xxx.dll和xxx.xml拷贝到稳定的目录(如框架类库目录: c:\windows\Microsoft.Net\Framework\v3.5\)下
// cmd中使用命令gacutil /i xxx.dll注册到GAC中 使用gacutil /u xxx.dll可以反注册; 若不需要xxx.xml, 可以简单的讲xxx.dll拖到c:\windows\Assemly文件夹中
/// <summary>
/// 描述定时关机操作及其相关信息
/// </summary>
public class Model
{
/// <summary>
/// 根据参数选择执行的操作及延时
/// </summary>
/// <param name="action">System.String类型, 表示操作的类型, "r"代表重启, "s"代表关机</param>
/// <param name="seconds">System.Int32类型, 以整数表示的操作延时, 单位为秒</param>
public void RunCommand(string action, int seconds)
{
string param = " -" + action + " -t " + seconds;
Process.Start("shutdown", param);
}
/// <summary>
/// 根据参数返回执行命令的字符串表示
/// </summary>
/// <param name="action">System.String类型, 表示操作额类型, "r"代表重启, "s"代表关机</param>
/// <param name="seconds">System.Int32类型, 以整数表示的操作延迟, 单位为秒</param>
/// <returns>System.String类型, 执行命令的字符串表示, 默认返回空字符串""</returns>
public string GetCommand(string action, int seconds)
{
string result = "";
result = "shutdown -" + action + " -t " + seconds;
return result;
}
}
}
//Model/AssemblyInfo.cs
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("PowerOffComponent")]
[assembly: AssemblyDescription("全局程序集, 完成计算机定时关机操作")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("China America IT Technology Inc.")]
[assembly: AssemblyProduct("CaitProduct-PowerOff")]
[assembly: AssemblyCopyright("Copyright © China America IT Technology Inc. 2010")]
[assembly: AssemblyTrademark("CAIT")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("43c452bd-72d8-421c-b2ec-4e8a9b749418")]
// Version information for an assembly consists of the following four values:
//
// Major Version: 主版本号, 软件版本重大变化, 如: 单机版到网络版
// Minor Version: 次要版本号, 软件功能变化, 如: 添加辅助挂机功能
// Build Number: 内部版本号, 如: beta,final, 或同时做出几个不同方案, 最终选一个
// Revision: 修订号: 修改bug的次数
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.1.5")]
[assembly: AssemblyFileVersion("1.0.1.5")]
//Controller/Controller.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MVCController
{
public class Controller
{
public static string KillPower(string choise, string time)
{
string result = null;
string param = (choise == "1") ? "s" : "r";
int inttime = Convert.ToInt32(time);
MVCModel.Model m = new MVCModel.Model();
result = m.GetCommand(param, inttime);
//这里可以采用异步通信, 开辟子线程执行RunCommand命令
m.RunCommand(param, inttime); //两种异步通信: 1. Async方法+事件 2.委托实例+回调函数(callback)
return result;
}
}
}
//View/View.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MVCView
{
class View
{
static void Main(string[] args)
{
Console.WriteLine("**************************************");
Console.WriteLine("* *");
Console.WriteLine("* MVC模式练习---关机重启小程序 *");
Console.WriteLine("* *");
Console.WriteLine("**************************************");
string input = "";
string time = "5";
string result = null;
while (true)
{
Console.WriteLine("请选择操作: \t1.关机 \t2.重启");
Console.WriteLine("\t\t0.退出");
input = Console.ReadLine();
if (input != "0")
{
if ((input == "1") != (input == "2"))
{
Console.Write("请输入延迟时间(含0): ");
time = Console.ReadLine();
//执行方法
result = MVCController.Controller.KillPower(input,time);
if (result != null)
{
Console.WriteLine("\n操作已执行, 执行的完整命令为: " + result+"\n");
}
else
{
Console.WriteLine("\n程序执行异常, 请通知管理员! \n");
}
}
else
{
Console.WriteLine("输入了不合适的选项! ");
}
}
else
{
Console.WriteLine("感谢使用, 再见! ");
break;
}
}
}
}
}
ASP.NET-MVC
最早是在王老师的课上听到MVC这个东西, 当时是讲设计模式. MVC设计模式从本质上讲就是种分工的方式, 人为的把一个项目分成Model(模型)、View(试图)、Controller(控制器). 这样呢, 首先由Controller来协调View和Model之间的衔接, 按王老师的话讲就是”和稀泥的家伙”, 在Controller中预先规定好需要提供给View开发人员的方法及方法名, 这样, View开发人员在开发时, 便可以忽略具体的实现, 只要根据需要调用Controller中的方法并显示结果即可; 那么Model开发人员关注的则是具体的业务对象, 针对每个业务对象制作不同的类以及与该业务对象相关的各种方法; 最后Controller通常有较有经验的工程师担当, 他负责调用Model中业务对象的各种方法来完成相关的业务逻辑. 如此, 一个项目就被分成了3个阶段, View和Controller、Controller和Model之间可以通过接口来现隔离(术语叫解耦合), 最终3个部分可以并行开发, 大大提高了开发效率.
之后在郝老师的课上, 又一次听到MVC, 这里的MVC是指ASP.NET的MVC开发方式(说开发模式容易混淆). 反正当时我是弄混了.
MVC设计模式: 何谓设计模式? 设计模式是一种设计思想, 是高于开发的一种抽象层面的想法. 而MVC开发模式或者说开发方式, 就是在你实际开发过程中, 采取的一种手段或某种流程. 前面也提过, MVC设计模式的思想就是分工, 各层用接口隔离; MVC开发模式是微软在ASP.NET技术中提出的一种开发手段, 就如同我们熟悉的WebForm开发, ASP.NET MVC也是一种开发手段与WebForm是平行的, 它代表.NET Web开发领域中, 除WebForm外的另一种开发方向. 你可以理解为ASP.NET MVC就是将MVC设计模式的思想用到了Web网站开发中的UI层, 所有ASP.NET MVC的工作都是针对UI层的, 底下的业务逻辑、数据库访问、实体等层依然和WebForm开发是一样的.
那么微软大费周章的搞出个ASP.NET MVC有什么好处呢? ----最大的好处就是可测试.
在传统的Web开发中, 如果想测试开发的网站, 你需要的启动网站, 用非正常用户的角度去尝试各种边界值和以外情况, 而在ASP.NET MVC中, 页面View中显示的内容都是从Model中来的, 而Model又是在Controller中由Action返回的, 这里先不用管Action是什么, 你可以把它当作是个Controller中的处理请求的方法. 此时, 整个Controller看起来就是类而已, 而实际上它就是个类, 这时候关于网站的测试工作的关键就看这个类了, 这时候你想到了什么? NUnitTest, 对啊, 我们只要写测试用例, 用事先写好的测试用例来测试不就好了, 开发过程中, 我们可以随时跑下测试用例, 就知道当前有没有错误. 因此, 可测试是ASP.NET MVC的最大优点.
ASP.NET MVC 请求过程:
说了一大堆, 其实就是两点: 1. ASP.NET MVC开发模式(方式)是MVC设计模式(思想)在UI层的体现. 2. ASP.NET MVC最大的优点是便于测试. Okey, 接下来开始ASP.NET MVC, 以下无特殊说明, MVC均指ASP.NET MVC. 看下图, ASP.NET MVC的请求回应过程.
客户端浏览器首先发送GET或POST请求, 当请求到达IIS后, 由aspnet_iisapi.dll转交asp.net组件, 然后由w3wp创建应用程序域, 再应用程序域中创建HttpRuntime执行环境, 并在环境中创建HttpContext对象(该对象包含HttpRequest、HttpResponse、Cache、Server等对象)和HttpApplication应用程序管道, 在HttpApplication应用程序管道中会根据请求的URL形式将会进行一个称为Routing的过程(可以参见Global.asax.cs中的代码). 什么是Routing(路由)呢? 在计算机网络中, 路由定义为: 在不同的网段间转发数据的过程. 而在此处的Routing可以理解为一个转发数据的过程, 它把GET请求头或POST请求体中的数据转发给了Controller. 上图中有个请求地址的示例, Routing的工作实际上就是通过正则表达式把Controller、Action和Parameter分别取出来. 这样, 便得到了Controller的名称、Action的名称、以及参数, 这时asp.net mvc将会到网站根目录下的Controllers文件夹中找到相应名称的Controller类, 并在Controller类中找到Action. 在Controller类中可以看到, 一个Action其实就是返回值为ActionResult的方法. 之后, 在Action方法中完成调用业务逻辑层、数据库访问层等完成工作之后, 将取到的结果封装到一个Model类中, 在返回给前台的View. 在View中通过该Model类的对象获得值并显示在View中, 最后在把View发送给客户端浏览器.
以上就是ASP.NET MVC的整个请求相应过程, 值得注意的, Model是用来封装返回结果的, 也可以在Model中添加用于验证(配合jQuery)的标注属性. 当然我们也可以不用Model, 而直接使用ViewData字典或者自定义实体类都可以返回结果. 不论是Model、ViewData还是实体类都需要在View的页面指令的Inherits属性中声明一下, 声明格式如下: Inherits =” System.Web.Mvc.ViewPage<mvc_1.Models.VenderModel>”, 其中mvc_1.Models.VenderModel就是用来封装结果的Model类.
如此说来, 我们有三种方式从Controller中传递数据岛View中: ViewData、自定义实体类、Model(常用).
开发ASP.NET MVC网站的开发工具需要是VS2008 + SP1以上, 并且需要安装ASP.NET MVC2_VS2008. 在写View的时候, 会用到Lambda表达式(Parameter => Method)和嵌入程序块(<%...%>)及嵌入表达式(<%= %>). 详见示例:
1. 为简便, 这里不再分BLL、DAL及实体层, 我们通过一个接口和一个实现类来完成对xml中数据的操作、通过Manufacturer实体类表示制造商信息.
注意: 在返回集合数据时, 可以用IEnumerable<T>泛型接口作返回类型.
Model类似于实体类, 但Model真的不是实体类:
实体类是与数据库中某张或某几张表相关的类型, 该类型可以使程序员在程序中方便的表示和使用表中的数据, 是O/R Mapping(Object-Relation Mapping, 对象关系映射)思想的体现. 实体类中几乎涉及数据表中的每个字段, 是用来在整个项目中表示数据对象的. 而Model中虽然也是一大堆封装字段的属性, 而且可以添加用于验证(配合jQuery)的标签属性, 但是Model的重点在于Controller和View之间. Model提供了一种介于Controller和View之间传递的数据的强类型表示, Model中的数据可能只是与View中需要显示的那部分数据相关. 一句话说, 实体类是数据库中的表 和程序中的数据表示 之间的一层映射, 而Model是UI层的Controller和View之间传递的数据或参数的映射. 例如: 你可能在数据中有表(包含: 序号、姓名、密码、生日、家庭住址), 那么你的实体类中往往是对表中所有字段的封装. 但是在UI中, 你的更改密码的页面(View)传递给Controller的参数往往是个Model类(包含: 旧密码、新密码)的对象, 这时区别很容易看出来. Model就是一种对传递的数据的强类型的封装, 而实体类是对数据库中表中字段进行的封装, 是用来在程序中表示表中的数据的. 根据具体的情况, Model类中字段的内容可能和实体类字段的内容相差很大, 更多的时候Model类中的字段就是View中用来接收用户输入的字段.
2. 由上图可知, 客户端请求的第一站是Controller中. 为实现低耦合, 我们在Controller中调用接口上的方法, 因为我们可以先定义接口类型的属性, 然后重写Controller的Initialize()方法, 在Initialize()方法中进行接口的赋值工作.
注意: 我们通常将业务逻辑处理完的结果用Model封装后返回给View, 但是当返回的是集合类型的元素时, 我们必须通过ViewData字典返回.
3. 接下来, 我们继续看Controller中的每个方法即Action, 每个Action应该对应一个View, 而Controller中往往有多个Action, 所以我们在View文件夹中创建Manufacturer文件夹, 并且针对每个Action都创建一个View页面, 如: Index、Detail、Delete等.
注意: 我们也可以自定义Action, 其实就是写个方法. 例如: public JsonResult CheckName(){…}, 其中JsonResult用来返回Json对象, 通过JsonResult对象的JsonRequestBehavior属性设置允许的请求类型, 通过JsonResult对象的Data属性返回结果.
在MVC中, 针对同一个View页面的两次请求会由于缓存看不到结果, 这是需要用页面指令关闭缓存. 如:<@OutputCache Duration=”1” VaryByParam=”*”%>
4. 最后, 在View中呈现我们的结果, 如果是集合数据, 我们可以采用嵌入代码块的方式(<%......%>)拼程序块, 而用<%=……%>来绑定结果中的字段; 如果返回的只是单个Model, 可以通过lambda表达式绑定结果数据, 只是不要忘了需要在页面指令的Inherits属性中, 申明Model.
以上便是Asp.Net MVC的一次请求过程, 开发网站的UI时, 只要按照Controller ---> Action ---> BLL(业务处理逻辑) ---> View的次序迭代即可.
关于MVC中的验证:
Model类中的标注属性实际上就是用来完成验证工作的, 因为Model类中的字段均是View页面中需要用户输入的字段, 凡是涉及到用户输入的地方, 肯定补课缺少的就是验证.
在MVC有两种验证方式: 服务器端的验证方式 和 客户端的验证方式.
1. 服务器端验证: 包含Model中的标注属性、View中的Html.ValidationMessageFor()、Controller中的Action方法中的ModelState.IsValid属性. MVC中的服务器端验证和jQuery的Validate配合工作的. 使用时, 只要在Model中添加验证标签(引用System.ComponentModel和System.ComponentModel.DataAnnotations命名空间), 在Controller的Action方法中用ModelState.IsValid判断下, 最后再View中添加验证信息的显示位置即可. 具体事例, 参见View文件夹中的Create.aspx.
2. 客户端验证: 客户端验证才是我们开发中常用的验证手段, 同样MVC的客户端的验证手段仍然是通过jQuery的Validate实现的. 客户端的验证, 我们不需要该Model、也不需要改Controller, 所有的验证工作都是在View中的Javascript脚本中完成的. 我们把jQuery和jQuery.Validate引用到View页面中, 并且我们可以通过Html.TextBoxFor()的重载方法, 为TextBox元素添加ID等属性(通过匿名对象new {}进行). 具体事例见Edit.aspx
注意: 我们可以通过<%= Url.Action(“ActionName”) %>计算出这个Action的全路径. 并且因为IE浏览器会对同一个请求做缓存处理, 所以这里应该用<%= Url.Action(“ActionName”) + “?” + DateTime.ToLongTimeString() %>做地址.
关于input中的name属性, 例如: <input type=”hidden” name=”abc” value=”123”>的标签, 只有添加了name属性, 在表达提交时才会将input的值发送到服务器. 发送时, 会在get请求后变成?abc=123,在post请求体中变成是…&abc=123, …表示装他的内容.
关于缓存, 我们有5中关闭缓存的方式:
1. 更改Url: 在Url后边人为添加不会重复的内容.
2. 在*.ashx, *.cs文件中用context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
3. 在*.aspx或*.ascx文件中, 用页面指令<%@Outputcache Duration=”1” VaryByParam=”*”%>
4. jQuery的Ajax中, 使用$.ajax({cache: false}); 关闭ajax时的缓存
5. 在*.html中的head标签中, 添加如下内容:
<META HTTP-EQUIV="pragma" CONTENT="no-cache">
<META HTTP-EQUIV="Cache-Control" CONTENT="no-cache, must-revalidate">
<META HTTP-EQUIV="expires" CONTENT="Wed, 26 Feb 1997 08:21:57 GMT">
//实例代码如下:
//数据文件, App_Data/ManufacturerData.xml
<?xml version="1.0" encoding="utf-8"?>
<Data>
<Manufacturer>
<ManufacturerID>fa33da90-d145-4122-85a9-b3f99f99ebfd</ManufacturerID>
<ManufacturerName>Mercedes.Benz</ManufacturerName>
<MandarinName>梅赛德斯.奔驰</MandarinName>
<CreateTime>2011-01-12 18:53:20</CreateTime>
</Manufacturer>
<Manufacturer>
<ManufacturerID>8f7f6a78-b991-493e-bbe7-4ba5af00fa63</ManufacturerID>
<ManufacturerName>Bayerische Motoren-Werke AG</ManufacturerName>
<MandarinName>宝马</MandarinName>
<CreateTime>2011-03-02 08:33:00</CreateTime>
</Manufacturer>
<Manufacturer>
<ManufacturerID>c3aa600a-26df-4a27-be06-4b4329f2998a</ManufacturerID>
<ManufacturerName>Ferrari</ManufacturerName>
<MandarinName>法拉利</MandarinName>
<CreateTime>2010-06-07 23:13:15</CreateTime>
</Manufacturer>
<Manufacturer>
<ManufacturerID>45d73ca9-96ad-4884-b56b-2b6b673d9843</ManufacturerID>
<ManufacturerName>cbg</ManufacturerName>
<MandarinName>Test1</MandarinName>
<CreateTime>2011-2-18 0:40:30</CreateTime>
</Manufacturer>
<Manufacturer>
<ManufacturerID>4c35a974-ecb4-489d-878b-0008f1735ba3</ManufacturerID>
<ManufacturerName>abc</ManufacturerName>
<MandarinName>vvvb </MandarinName>
<CreateTime>2011-2-18 1:45:06</CreateTime>
</Manufacturer>
</Data>
//IManufacturerManager.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MvcApplicationDemo
{
public interface IManufacturerManager
{
//当返回集合数据时, 可以用IEnumerable<T>泛型接口作返回类型
IEnumerable<Manufacturer> GetAllManufacturers();
Manufacturer GetManufacturerByID(Guid id);
void CreateManufacturer(Manufacturer manufacturer);
void DeleteManufacturer(Guid id);
bool CheckManufacturerName(string manufacturername);
void UpdateManufacturer(Manufacturer manufacturer);
}
}
//ManufacturerManager.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace MvcApplicationDemo
{
public class ManufacturerManager : IManufacturerManager
{
string DataPath = AppDomain.CurrentDomain.BaseDirectory + "App_Data/ManufacturerData.xml";
#region IManufacturerManager Members
public IEnumerable<Manufacturer> GetAllManufacturers()
{
//一次性全部读取, 适合采用XML流, 但XML流不支持结构化查询
List<Manufacturer> manufacturers = new List<Manufacturer>(); //用于返回数据
System.IO.StreamReader sw = new System.IO.StreamReader(DataPath, System.Text.Encoding.UTF8);
using (System.Xml.XmlReader xmlrd = System.Xml.XmlReader.Create(sw))
{
Manufacturer manufacturer;
while (xmlrd.Read())
{
if (xmlrd.NodeType == System.Xml.XmlNodeType.Element)
{
if (xmlrd.Name == "Manufacturer")
{
manufacturer = new Manufacturer();
if (xmlrd.ReadToFollowing("ManufacturerID"))
{
manufacturer.Uid = new Guid(xmlrd.ReadElementString("ManufacturerID"));
}
if (xmlrd.ReadToFollowing("ManufacturerName"))
{
manufacturer.ManufacturerName = xmlrd.ReadElementString("ManufacturerName");
}
if (xmlrd.ReadToFollowing("MandarinName"))
{
manufacturer.MandarinName = xmlrd.ReadElementString("MandarinName");
}
if (xmlrd.ReadToFollowing("CreateTime"))
{
manufacturer.CreateTime = DateTime.Parse(xmlrd.ReadElementString("CreateTime"));
}
manufacturers.Add(manufacturer);
}
}
}
}
sw.Close();
return manufacturers;
}
public Manufacturer GetManufacturerByID(Guid id)
{
Manufacturer manufacturer = null;
//只是查询, 适合XPathDocument, 优化过的XPath, 优点: 结构化查询、速度快; 缺点: 只能读不能写
System.Xml.XPath.XPathDocument xpdoc = new System.Xml.XPath.XPathDocument(DataPath); //创建XPathDocument
System.Xml.XPath.XPathNavigator xpnav = xpdoc.CreateNavigator(); //创建查找用的导航器
//定制XPathExpression表达式
string xpathstr = "Data/Manufacturer";
System.Xml.XPath.XPathExpression xpath = System.Xml.XPath.XPathExpression.Compile(xpathstr);
//使用导航器获得结果, 单个结果用XPathNavigator导航器, 多个结果用XPathNodeIterator迭代器
System.Xml.XPath.XPathNavigator resultnav = xpnav.SelectSingleNode(xpathstr);
while (resultnav.HasChildren)
{
resultnav.MoveToFirstChild();
if (resultnav.Value == id.ToString())
{
manufacturer = new Manufacturer();
manufacturer.Uid = id;
if (resultnav.MoveToNext() && resultnav.Name == "ManufacturerName")
{
manufacturer.ManufacturerName = resultnav.Value;
}
if (resultnav.MoveToNext() && resultnav.Name == "MandarinName")
{
manufacturer.MandarinName = resultnav.Value;
}
if (resultnav.MoveToNext() && resultnav.Name == "CreateTime" && !string.IsNullOrEmpty(resultnav.Value))
{
manufacturer.CreateTime = DateTime.Parse(resultnav.Value);
}
break;
}
else
{
resultnav.MoveToParent(); ; //移动父节点
resultnav.MoveToNext(); //父节点的兄弟
}
}
return manufacturer;
}
public void CreateManufacturer(Manufacturer manufacturer)
{
//修改操作, 适合采用XPath进行操作
System.Xml.XmlDocument xdoc = new System.Xml.XmlDocument();
xdoc.Load(DataPath);
string xpath = "/Data";
System.Xml.XmlNode nodes = xdoc.SelectSingleNode(xpath);
System.Xml.XmlNode newnode = xdoc.CreateNode(System.Xml.XmlNodeType.Element, "Manufacturer", string.Empty);
System.Xml.XmlElement elemid = xdoc.CreateElement("ManufacturerID");
System.Xml.XmlText textid = xdoc.CreateTextNode(manufacturer.Uid.ToString());
elemid.AppendChild(textid);
newnode.AppendChild(elemid);
System.Xml.XmlElement elemname = xdoc.CreateElement("ManufacturerName");
System.Xml.XmlText textname = xdoc.CreateTextNode(manufacturer.ManufacturerName);
elemname.AppendChild(textname);
newnode.AppendChild(elemname);
System.Xml.XmlElement elemcnname = xdoc.CreateElement("MandarinName");
System.Xml.XmlText textcnname = xdoc.CreateTextNode(manufacturer.MandarinName);
elemcnname.AppendChild(textcnname);
newnode.AppendChild(elemcnname);
System.Xml.XmlElement elemtime = xdoc.CreateElement("CreateTime");
System.Xml.XmlText texttime = xdoc.CreateTextNode(manufacturer.CreateTime.ToString());
elemtime.AppendChild(texttime);
newnode.AppendChild(elemtime);
nodes.AppendChild(newnode);
using (System.IO.StreamWriter sw = new System.IO.StreamWriter(DataPath, false, System.Text.Encoding.UTF8))
{
xdoc.Save(sw);
}
}
public void DeleteManufacturer(Guid id)
{
//修改操作, 适合采用XPath进行操作
System.Xml.XmlDocument xdoc = new System.Xml.XmlDocument();
xdoc.Load(DataPath);
string xpath = "/Data/Manufacturer/ManufacturerID [text()=\""+id.ToString()+"\"]";
System.Xml.XmlNode node = xdoc.SelectSingleNode(xpath);
if (node != null)
{
node.ParentNode.ParentNode.RemoveChild(node.ParentNode);
}
using (System.IO.StreamWriter sw = new System.IO.StreamWriter(DataPath, false, System.Text.Encoding.UTF8))
{
xdoc.Save(sw);
}
}
public void UpdateManufacturer(Manufacturer manufacturer)
{
//修改操作, 适合采用XPath进行操作
System.Xml.XmlDocument xdoc = new System.Xml.XmlDocument();
xdoc.Load(DataPath);
string xpath = "/Data/Manufacturer/ManufacturerID [text()=\"" + manufacturer.Uid.ToString() + "\"]";
System.Xml.XmlNode node = xdoc.SelectSingleNode(xpath);
if (node != null)
{
node.NextSibling.FirstChild.Value = manufacturer.ManufacturerName;
node.NextSibling.NextSibling.FirstChild.Value = manufacturer.MandarinName;
}
using (System.IO.StreamWriter sw = new System.IO.StreamWriter(DataPath, false, System.Text.Encoding.UTF8))
{
xdoc.Save(sw);
}
}
public bool CheckManufacturerName(string manufacturername)
{
//仅查找, 适合XPathDocument
System.Xml.XPath.XPathDocument xpd = new System.Xml.XPath.XPathDocument(DataPath);
System.Xml.XPath.XPathNavigator xnav = xpd.CreateNavigator();
//定义XPath
string xpathstr = "/Data/Manufacturer/ManufacturerName [text()=\"" + manufacturername + "\"]";
System.Xml.XPath.XPathExpression xpath = System.Xml.XPath.XPathExpression.Compile(xpathstr);
System.Xml.XPath.XPathNavigator result = xnav.SelectSingleNode(xpath);
if (result == null)
{
return true;
}
else
{
return false;
}
}
#endregion
}
}
//实体类, Manufacturer.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace MvcApplicationDemo
{
public class Manufacturer
{
public Guid Uid { get; set; }
public string ManufacturerName { get; set; }
public string MandarinName { get; set; }
public DateTime CreateTime { get; set; }
public Manufacturer()
{ }
public Manufacturer(Guid id, string manufacturername, string mandarinname, DateTime createtime)
{
this.Uid = id;
this.ManufacturerName = manufacturername;
this.MandarinName = mandarinname;
this.CreateTime = createtime;
}
public Manufacturer(Guid id, string manufacturername, DateTime createtime)
{
this.Uid = id;
this.ManufacturerName = manufacturername;
this.MandarinName = string.Empty;
this.CreateTime = createtime;
}
}
}
//Controllers/ManufacturerController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace MvcApplicationDemo.Controllers
{
public class ManufacturerController : Controller
{
//通过接口来调用方法, 在初始化方法中用接口承载实现类
public IManufacturerManager ManufacturerService { get; set; }
protected override void Initialize(System.Web.Routing.RequestContext requestContext)
{
if (this.ManufacturerService == null)
{
this.ManufacturerService = new ManufacturerManager();
}
base.Initialize(requestContext);
}
//
// GET: /Manufacturer/
public ActionResult Index()
{
IEnumerable<Manufacturer> manufacturers = this.ManufacturerService.GetAllManufacturers();
//由于ManufacturerModel无法传递集合, 这里用ViewData传递集合数据
ViewData["manufacturers"] = manufacturers;
return View();
}
//
// GET: /Manufacturer/Details/5
public ActionResult Details(Guid id) //修改int类型为GUID
{
Manufacturer manufacturer = this.ManufacturerService.GetManufacturerByID(id);
return View(manufacturer); //显示全部信息, 这里用实体类返回数据给View, 注意在View中注册Manufacturer类型
}
//
// GET: /Manufacturer/Create
public ActionResult Create() //Get方式
{
return View();
}
//
// POST: /Manufacturer/Create
[HttpPost]
public ActionResult Create(MvcApplicationDemo.Models.ManufacturerModel model) //使用Model传递数据
{
if (ModelState.IsValid) //Model是否通过验证, 验证工作通过Model类的标注属性完成(服务器端验证)
{
try
{
// TODO: Add insert logic here
Manufacturer manufacturer = new Manufacturer(Guid.NewGuid(), model.ManufacturerName, model.MandarinName, DateTime.Now);
this.ManufacturerService.CreateManufacturer(manufacturer);
return RedirectToAction("Index");
}
catch
{
return View();
}
}
return View(model);
}
//
// GET: /Manufacturer/Edit/5
public ActionResult Edit(Guid id)
{
if (id != Guid.Empty)
{
Manufacturer manufacturer = this.ManufacturerService.GetManufacturerByID(id);
MvcApplicationDemo.Models.ManufacturerModel model = new MvcApplicationDemo.Models.ManufacturerModel();
model.ManufacturerName = manufacturer.ManufacturerName;
model.MandarinName = manufacturer.MandarinName;
return View(model); //用Model返回数据
}
else
{
return View();
}
}
//
// POST: /Manufacturer/Edit/5
[HttpPost]
public ActionResult Edit(Guid id, MvcApplicationDemo.Models.ManufacturerModel model)
{
try
{
// TODO: Add update logic here
Manufacturer manufacturer = new Manufacturer();
manufacturer.Uid = id;
manufacturer.ManufacturerName = model.ManufacturerName;
manufacturer.MandarinName = model.MandarinName;
this.ManufacturerService.UpdateManufacturer(manufacturer);
return RedirectToAction("Index");
}
catch
{
return View();
}
}
//
// GET: /Manufacturer/Delete/5
public ActionResult Delete(Guid id)
{
if (id != Guid.Empty)
{
this.ManufacturerService.DeleteManufacturer(id);
}
return RedirectToAction("Index");
}
//
// POST: /Manufacturer/Delete/5
//[HttpPost] //删除不需要Post方式
//public ActionResult Delete(Guid id, FormCollection collection)
//{
// try
// {
// // TODO: Add delete logic here
// if (id != null)
// {
// this.ManufacturerService.DeleteManufacturer(id);
// }
// return RedirectToAction("Index");
// }
// catch
// {
// return View();
// }
//}
//添加自定义的Action
public ActionResult CheckManufacturerName(string manufacturername)
{
if (!string.IsNullOrEmpty(manufacturername))
{
//JsonResult专门用来返回Json对象
JsonResult jresult = new JsonResult();
jresult.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
jresult.Data = this.ManufacturerService.CheckManufacturerName(manufacturername);
return jresult;
}
return View();
}
}
}
//Models/ManufacturerModel.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace MvcApplicationDemo.Models
{
public class ManufacturerModel
{
[System.ComponentModel.DataAnnotations.Required]
[System.ComponentModel.DisplayName("制造商名称")] //文本框前的文本信息, 需要配合LabelFor()
public string ManufacturerName { get; set; }
[System.ComponentModel.DataAnnotations.Required]
[System.ComponentModel.DisplayName("中文名称")]
public string MandarinName { get; set; }
}
}
//Views/Shared/Site.Master
<%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title><asp:ContentPlaceHolder ID="TitleContent" runat="server" /></title>
<link href="http://www.cnblogs.com/Content/Site.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div class="page">
<div id="header">
<div id="title">
<h1>My MVC Application</h1>
</div>
<div id="logindisplay">
<% Html.RenderPartial("LogOnUserControl"); %>
</div>
<div id="menucontainer">
<ul id="menu">
<li><%= Html.ActionLink("Home", "Index", "Home")%></li>
<li><%= Html.ActionLink("About", "About", "Home")%></li>
<li><%= Html.ActionLink("Manufacturer", "Index", "Manufacturer")%></li>
</ul>
</div>
</div>
<div id="main">
<asp:ContentPlaceHolder ID="MainContent" runat="server" />
<div id="footer">
</div>
</div>
</div>
</body>
</html>
//Views/Manufacturer/Index.aspx
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %>
<%@OutputCache Duration="1" VaryByParam="*" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
制造商
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>制造商</h2>
<%= Html.ActionLink("添加","Create") %>
<hr />
<% var manufacturers = ViewData["manufacturers"] as IEnumerable<MvcApplicationDemo.Manufacturer>; %>
<table>
<tr>
<td>制造商ID</td>
<td>制造商名称</td>
</tr>
<%
foreach (var m in manufacturers)
{
%>
<tr>
<td><%= Html.Encode(m.Uid) %></td><%--Encode用来防止用户直接输入Html元素--%>
<td><%= Html.Encode(m.ManufacturerName)%></td>
<td><%= Html.ActionLink("详细", "Details", new { id = m.Uid } )%></td>
<td><%= Html.ActionLink("修改", "Edit", new { id = m.Uid } )%></td>
<td><%= Html.ActionLink("删除", "Delete", new { id = m.Uid } )%></td>
</tr>
<%}%>
</table>
</asp:Content>
//Views/Manufacturer/Details.aspx
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<MvcApplicationDemo.Manufacturer>" %>
<%@OutputCache Duration="1" VaryByParam="*" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
制造商详情
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>制造商详情</h2>
<%= Html.ActionLink("修改","Edit",new { id = ViewData.Model.Uid} )%>
<%= Html.ActionLink("返回","Index") %>
<hr />
<ul>
<li><%= Html.Encode(ViewData.Model.Uid) %></li>
<li><%= Html.Encode(ViewData.Model.ManufacturerName) %></li>
<li><%= Html.Encode(ViewData.Model.MandarinName) %></li>
<li><%= Html.Encode(ViewData.Model.CreateTime) %></li>
<%--<li><%= Html.Encode(ViewData.Eval("CreateTime"))%></li>--%>
</ul>
</asp:Content>
//Views/Manufacturer/Create.aspx
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<MvcApplicationDemo.Models.ManufacturerModel>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
添加制造商
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>添加制造商</h2>
<% Html.BeginForm(); %>
<fieldset>
<legend>制造商信息</legend>
制造商名称: <%= Html.TextBoxFor(m => m.ManufacturerName)%>
<%= Html.ValidationMessageFor(m => m.ManufacturerName) %><br />
中文名称: <%= Html.TextBoxFor(m => m.MandarinName)%>
<%= Html.ValidationMessageFor(m => m.MandarinName) %><br />
<br />
<input type="submit" value="保存" />
</fieldset>
<% Html.EndForm(); %>
</asp:Content>
//Views/Manufacturer/Edit.aspx
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<MvcApplicationDemo.Models.ManufacturerModel>" %>
<%@ OutputCache Duration="1" VaryByParam="*" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Edit
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>
修改制造商信息</h2>
<%= Html.ActionLink("返回","Index") %>
<% Html.BeginForm(); %>
<fieldset>
<legend>制造商信息</legend>制造商名称:
<%= Html.TextBoxFor(m => m.ManufacturerName, new { id="ManuName"})%>
<span></span>
<br />
中文名称:
<%= Html.TextBoxFor(m => m.MandarinName)%>
<span></span>
<br />
<input type="submit" value="保存" />
</fieldset>
<% Html.EndForm(); %>
<script src="http://www.cnblogs.com/Scripts/jquery-1.4.1-vsdoc.js" type="text/javascript"></script>
<script src="http://www.cnblogs.com/Scripts/jquery.validate-vsdoc.js" type="text/javascript"></script>
<script type="text/javascript">
//关闭缓存的做法: 1.修改Url 2.设置Ajax关闭缓存 3.<OutputCache> 4.<META HTTP-EQUIV="Pragma" CONTENT="no-cache"><META HTTP-EQUIV="Expires" CONTENT="-1">
// $.ajax({
// cache: false
// });
$(function() {
//alert("hello");
$("form").validate(
//通过一个参数对象描述验证信息
{
rules: {
ManufacturerName: {
required: true,
minlength: 2,
remote: '<%=Url.Action("CheckManufacturerName") + "?" + DateTime.Now.ToLongTimeString() %>'
},
MandarinName: {
minlength: 2
}
},
messages: {
ManufacturerName: {
required: "必须输入供应商名称",
minlength: jQuery.format("供应商名称至少包含 {0} 个字符"),
remote: "供应商已经存在,请检查名称。"
},
MandarinName: {
minlength: jQuery.format("中文名称至少包含 {0} 个字符")
}
},
errorPlacement: function(error, element) {
error.appendTo(element.next("span"));
},
success: function(label) {
// set as text for IE
label.html(" ").addClass("checked");
}
});
})
</script>
</asp:Content>
//Global.asax.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
namespace MvcApplicationDemo
{
// Note: For instructions on enabling IIS6 or IIS7 classic mode,
// visit http://go.microsoft.com/?LinkId=9394801
public class MvcApplication : System.Web.HttpApplication
{
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
);
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
//注册路由
RegisterRoutes(RouteTable.Routes);
}
}
}