[IIS]没有对“C:\WINDOWS\Microsoft.NET\Framework\v2.0.5

mikel阅读(705)

在IIS中 发布程序一个ASP.NET程序,通过IE访问报如下错误:

当前标识(NT AUTHORITY\NETWORK SERVICE)没有对“C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files”访问权限
说明: 执行当前 Web 请求期间,出现未处理异常。请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误出处详细信息。
异常详细信息: System.Web.HttpException: 当前标识(NT AUTHORITY\NETWORK SERVICE)没有对“C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files”访问权限
源错误:
执行当前 Web 请求期间生成了未处理异常。可以使用下面异常堆栈跟踪信息确定有关异常原因和发生位置信息。
堆栈跟踪:
。。。。。。

=====================================

翻阅了一些资料后发现是需要重新注册IIS服务扩展,在“开始”-“运行”里输入如入命令,回车,搞定

C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_regiis -i -enable

冠亿科技,尽心尽力

[MVC]ASP.NET MVC:为视图自定义辅助方法(上)

mikel阅读(780)

转载: http://www.cnblogs.com/JeffreyZhao/archive/2009/04/29/custom-view-helpers-1.html

 在编写ASP.NET MVC应用程序时,只依赖内置的视图辅助方法很难达到很高的生产力,即使是定义在MvcFutures中的补充类库,也很难满足项目的具体需求。此外,不 同的项目有不同的特点,在很多时候也需要定义较为特殊的辅助方法,使开发人员能够更快,更方便地写出更容易维护的代码。这也是自定义视图辅助方法最主要的 目的(没有之一)。而这次的文章,便是给出一个这方面的示例,可作为此类问题的一个参考。

预备

  在编写客户端HTML时,进行客户端验证是最常见的工作之一。既然ASP.NET MVC集成了JQuery类库,那么我们不妨基于JQuery的Validate插件编写这部分功能。假设有如下表单:

<form method="post" action="" id="form">
<p>
<span>Name: </span> <!-- 必填 -->
<input type="text" name="user.Name" />
</p>
<p>
<span>Age: </span> <!-- 必填,15到28之间的数字 -->
<input type="text" name="user.Age" />
</p>
<p>
<span>Email:</span> <!-- 必填,且为合法Email -->
<input type="text" name="user.Email" />
</p>
<input type="submit" value="Submit" />
</form>

  如果使用JQuery Validate插件进行客户端校验,那么我们可以编写如下代码:

<script language="javascript" type="text/javascript">
$("#form").validate({
"rules": {
"user.Name": { "required": true },
"user.Age": {
"required": true,
"number": true,
"range": [15, 28]
},
"user.Email": {
"required": true,
"email": true
}
},
"messages": {
"user.Name": { "required": "please provide your name!!!" },
"user.Email": {
"required": "email please...",
"email": "valid email please..."
}
}, "onkeyup": false
});
</script>

  以上这段脚本的作用便是告诉jQuery校验哪个表单,对表单中的各个元素分别采取哪种校验方式,以及在发生错误的时候该提示什么信息(详细内 容可查阅文档)。这里可能需要补充一段题外话。实际上jQuery.Validate非常灵活,可以有各种方式提供校验信息,例如直接为html元素加特 殊标记。不过老赵认为那些方法的trick意味太浓,且不容易编写辅助方法协助开发,因此刻意忽略那些方式。

  这样的结果可能会招一些前台开发人员欢喜,不过老赵觉得,至少有三个地方需要提高:

  1. 数据分散,提高维护难度。例如HTML元素和校验规则分离,校验规则
  2. 对于开发人员来说,编写JSON较不方便,容易发生错误。
  3. 缺少对于“自动校验”的支持,需要完全手写。

  而我们编写的辅助方法,主要就是面向前两点,而最后一点可以说是自然而然的事情。

入口

  任何方法都需要一个入口,这个入口可能是某个静态类,甚至直接定义在global下最直接的“方法”。而ASP.NET MVC视图的辅助方法的入口往往定义在ViewPage中。例如与HTML相关的辅助方法定义在ViewPage.Html属性下,而与URL相关的辅助 方法都定义在ViewPage.Url属性下(ViewUserControl和ViewMasterPage情况也一样)。这样的入口区分,其实也是为 辅助方法进行了分类,也让用户可以在IDE的帮助下快速定位到所需的辅助方法。在编写一些简单的自定义辅助方法时,我们可以利用C# 3.0的扩展方法特性,将方法定义在HtmlHelper和UrlHelper上,这样便可直接在页面上使用。而对于一些特殊情况,例如目前的状况,我们 便需要重新定义一个入口,以便我们的辅助方法可以以此作为基础进行扩展。为此,我们把这一重担交给JQueryHelper类:

public class JQueryHelper
{
public JQueryHelper(ViewContext viewContext, ViewPage page)
: this(viewContext, page, RouteTable.Routes)
{ }
public JQueryHelper(
ViewContext viewContext,
ViewPage page,
RouteCollection routeCollection)
{
this.ViewContext = viewContext;
this.Page = page;
this.RouteCollection = routeCollection;
}
public RouteCollection RouteCollection { get; private set; }
public ViewContext ViewContext { get; private set; }
public ViewPage Page { get; private set; }
}

  生成JQueryHelper对象时,我们会保留目前的上下文,让各种扩展方法自行选用。至于保留哪些成员,这并没有太多限制,一般来说够用便 可,如有不足,我们按需补充便是。接下来便是要让页面可以访问到这个辅助对象了,与Html和Url这些现有的入口不同,我们使用扩展方法,而不是属性来 提供入口。这样做的好处便是在毫无侵入的情况,提供了较为友好的语法,这也是扩展方法的美妙之处:

public static class JQueryExtensions
{
public static JQueryHelper JQuery(this ViewPage page)
{
var key = typeof(JQueryHelper);
var jquery = page.Items[key] as JQueryHelper;
if (jquery == null)
{
page.Items[key] = jquery = new JQueryHelper(page.ViewContext, page);
}
return jquery;
}
}

  ViewPage的Items属性是一个页面级别的存储容器,可以使用键/值的方式存放任意数据,我们这里便利用这个特性,为每个页面提供唯一的JQueryHelper对象。

校验

  因为一个页面可能有多个需要校验的区域,因此我们需要提供一个机制,能够保存多个“批次”的校验信息。于是,我们编写一个JQueryValidation类用来存放“一批”校验信息:

public class JQueryValidation
{
public JQueryValidation(ViewPage page)
{
this.Page = page;
}
public ViewPage Page { get; private set; }
...
}

  当然,在JQueryHelper这个入口上,需要有一个访问校验信息的方式。在这里,我们使用字符串来标识“一批”校验信息。此外,我们也提供了默认重载以方便某些简单场景下的使用:

public static class JQueryValidationExtensions
{
public static JQueryValidation Validate(this JQueryHelper jquery)
{
return jquery.Validate("(default)");
}
public static JQueryValidation Validate(this JQueryHelper jquery, string name)
{
var key = typeof(JQueryValidation) + "+" + name;
var page = jquery.Page;
var validation = page.Items[key] as JQueryValidation;
if (validation == null)
{
page.Items[key] = validation = new JQueryValidation(page);
}
return validation;
}
}

  作了那么多的铺垫,接下来便是最关键辅助方法编写了。通过对JavaScript代码进行分析之后,我们决定采用典型的“记录 – 汇总”模式来编写这个方法1。“记录 – 汇总”模式的原则便是通过“记录”将信息汇总后输出,在作为页面辅助方法时,我们可以在任何地方“记录”校验信息,然后在合适的地方输出一段汇总后的脚本。由于我们所需要的JavaScript非常规整,因此实现这个需求并不困难。

  首先是记录,对于每个

public class JQueryValidation
{
private Dictionary<string, Dictionary<string, object>> m_rules =
new Dictionary<string, Dictionary<string, object>>();
private Dictionary<string, Dictionary<string, string>> m_messages =
new Dictionary<string, Dictionary<string, string>>();
private void AddRuleAndMessage(string name, string rule, object value, string m
{
if (!this.m_rules.ContainsKey(name))
this.m_rules[name] = new Dictionary<string, object>();
this.m_rules[name][rule] = value;
if (!String.IsNullOrEmpty(message))
{
if (!this.m_messages.ContainsKey(name))
this.m_messages[name] = new Dictionary<string, string>();
this.m_messages[name][rule] = message;
}
}
public void Required(string name, string message)
{
this.AddRuleAndMessage(name, "required", true, message);
}
public void Email(string name, string message)
{
this.AddRuleAndMessage(name, "email", true, message);
}
public void Number(string name, string message)
{
this.AddRuleAndMessage(name, "number", true, message);
}
public void Range(string name, int min, int max, string message)
{
this.AddRuleAndMessage(name, "range", new int[] { min, max }, message);
}
...
}

  我们使用两个字典分别存放规则的描述(m_rules)与错误提示(m_messages),由于信息的统一,我们只需编写一个 AddRuleAndMessage方法便可满足所有需要,而其他的方法只是定义了一个良好的接口,然后简单地把信息委托给 AddRuleAndMessage而已。

  最后便是汇总,我们使用JavaScriptSerializer把规模的描述与错误提示序列化成JSON字符串并输出:

public string ToScripts(string form)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
StringBuilder builder = new StringBuilder();
builder.Append("$(");
serializer.Serialize(form, builder);
builder.Append(").validate(");
serializer.Serialize(
new
{
rules = this.m_rules,
messages = this.m_messages,
onkeyup = false
}, builder);
builder.Append(");");
return builder.ToString();
}

使用

  “记录 – 汇总”,无它耳。

<form method="post" action="" id="form">
<p>
<span>Name: </span> <!-- 必填 -->
<input type="text" name="user.Name" />
<% this.JQuery().Validate().Required("user.Name", "please provide your name!!!"); %>
    </p>
<p>
<span>Age: </span> <!-- 必填,15到28之间的数字 -->
<input type="text" name="user.Age" />
<% this.JQuery().Validate().Required("user.Age", null); %>
        <% this.JQuery().Validate().Number("user.Age", null); %>
        <% this.JQuery().Validate().Range("user.Age", 15, 28, null); %>
    </p>
<p>
<span>Email:</span> <!-- 必填,且为合法Email -->
<input type="text" name="user.Email" />
<% this.JQuery().Validate().Required("user.Email", "email please..."); %>
        <% this.JQuery().Validate().Email("user.Email", "valid email please..."); %>
    </p>
<input type="submit" value="Submit" />
</form>
<script language="javascript" type="text/javascript">
<%= this.JQuery().Validate().ToScripts("#form") %>
</script>

  请看最后生成的HTML:

<script language="javascript" type="text/javascript">
$("#form").validate({ "rules": { "user.Name": { "required": true }, …
</script>

  因为编写了客户端辅助方法,我们已经把繁冗的客户端脚本变成了可以由Visual Studio提示并轻易输出的服务器端辅助方法——您觉得如何,是否满意?

  其实老赵还不满意,不过接下去的工作,我们下次再继续吧。

 

注1:什么?您说没有听说过“记录 – 汇总”这个模式?嗯,这是正常的,因为这是老赵“发明”的模式之一。

[MVC][一步一步MVC]第六回:MVC范例大观园

mikel阅读(888)

MVC是个新鲜的东西,至少为ASP .NET Web世界带来或多或少的争议,褒奖者有之,诋毁者有之。这也正常,人类的思维确实没法统一,即便是多个选择其实是件好事儿也一样。不管怎样,评说者至少 应该在了解的基础上再进行评论,才显得“专业”,没有品味的找茬型选手实在不值得恭维。

作为MVC范例集锦,我将MVC发布之后业界的应用开源项目做个简单的整理,Anytao不打算对任何项目发表个人观点,因为有些项目未经本人了解,所以此处仅是one by one式的陈列,期望对学习者有些帮助而已。

NerdDinner随着ScottGu、Phli几位大牛为作品《Professional ASP.NET MVC 1.0》谱写的辅助系统,同时通过一个在线系统http://www.nerddinner.com/以生动的实例来展现MVC技术,NerdDinner示例贯穿全书,尤其是第一章的Walkthrough可以让我们对MVC有个初次了解。

该范例是ASP.NET/mvc的讲解实例,因为它太简单以至于没有什么好说的,初入MVC的同学可以关注一下,安装step by step的方式构建自己的Contact Management应用。

不知为什么范例程序常常以Store来演示(例如Petshop),可能的原因是Store应用简单而全面,所以MVCStore应用也是这样一个简化示例, 我们可以研究研究。

业界对Oxite有不少批评Rob Conery是最尖锐的一个,作为“号称”微软MVC范例的Oxite,虽有些细可圈可点,但是离微软官方范例的角度确实还有距离。园子的代震军发表的关于两个MVC示例的思考(MVCStore和Oxite),对此进行的讨论或许可以给您以思考,从应用角度而言Oxite其实并非一无是处,很多点上还是有不错的运用,例如关于ActionFilter和IoC的应用是值得参考的。

Kigg是Codeplex上开源项目,从项目规模上而言,Kigg属于“大块头”,以MVC为基础架构,同时设计很多技术应用,单元测试也有不错可借鉴的地方。

Ezsocio至少可以是个范例,一套基于微软.NET平台的Social Network Software(SNS)系统,会用到许多最新开发技术,如ASP.NET MVC、LINQ、WCF、Unity、JQuery等,虽然还是个半成品,但是作为对于MVC学习和了解角度而言,还是“够用的”。例如以Unity为 容器的IoC设计、JQuery在MVC的应用、Validation、Cryptography、Repository模式等,好了不做广告了,那只是 个还没有完成的作品。

Sharp-Architecture是MVC和NHibernate应用范例,作为号称“Sharp Architecture”的应用,我想一定可以为我们呈现不一样的设计,对于了解MVC和NHibernate的人或许是个不错的选择。

fubumvc,可以看作是for us by us MVC,是老赵同志推荐给我的。fubumvc在了解ASP .NET MVC核心架构的基础上,表达了作者“不同意”ASP .NET MVC对于设计的理解,所以几个人凑在一起合谋了fubumvc Framework。这里,有一些关于FubuMVC和ASP .NET MVC的区别。

 

既然是大观园,可能以后还有补充,谁有更好的分享也可以在留言提供给我,以方便大家“有底放肆”。至于品评和讨论,还是放在以后吧。

 

更多关注,尽在anytao.net/blog

 

anytao | © 2009 Anytao.com

2009/04/29 | http://anytao.cnblogs.com/ | http://anytao.net/blog/post/2009/04/28/anytao-mvc-06-mvcsamples.aspx

本文以“现状”提供且没有任何担保,同时也没有授予任何权利。 | This posting is provided "AS IS" with no warranties, and confers no rights.

本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

[C#].net反射技术封装

mikel阅读(717)

如果有人问你,如何调用一个类的private的方法或访问一个类的私有成员,如果你不知道反射的话,你会告诉他不可以。但是有了反射,这一切都成为可 能。我有时候会想,既然使用private来限制访问,为什么又要用反射去破坏这种限制呢?也许可以通过侧面来解释这个问题,如果你要维护类的封装性,那 请不要用反射,反射会破坏类的封装性。
    但反正某些情况下,又会变得相当地有用,比如你有一个dll,其中很多类被声明为internal,如果你要使用这些类,而又无法修改源代码的话,你就可以使用反射了,最近总结了一下,对反射做了一个封装。由于代码比较简单,没有做注释。

using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
namespace UsefulUtility
{
    public class Invoker
    {
        private static BindingFlags flags = BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.IgnoreCase;
        public static Type GetType(Assembly asm, string typeFullName)
        {
            return asm.GetType(typeFullName);
        }
        public static Type GetInnerType(string hiddenTypeName, Type outerType)
        {
            Module typeModule = outerType.Module;
            return typeModule.GetType(hiddenTypeName);
        }
        public static MethodInfo GetMethod(Type type, string funcName, Type[] paramTypes)
        {
            if (paramTypes != null)
                return type.GetMethod(funcName, flags, null, paramTypes, null);
            else
                return type.GetMethod(funcName, flags);
        }
        public static MethodInfo GetMethod(Type type, string funcName)
        {
            return GetMethod(type, funcName, null);
        }
        public static object CallMethod(object obj, string funcName, params object[] parameters)
        {
            Type type = obj.GetType();
            MethodInfo method = GetMethod(type, funcName, GetTypesFromObjects(parameters));
            return method.Invoke(obj, parameters);
        }
        public static object CallStaticMethod(Type type, string funcName, params object[] parameters)
        {
            MethodInfo method = GetMethod(type, funcName, GetTypesFromObjects(parameters));
            return method.Invoke(null, parameters);
        }
        public static object GetProperty(object obj, string propertyName)
        {
            return GetProperty(obj, propertyName, null);
        }
        public static object GetProperty(object obj, string propertyName, params object[] index)
        {
            Type type = obj.GetType();
            return type.GetProperty(propertyName, flags).GetValue(obj, index);
        }
        public static object GetStaticProperty(Type type, string propertyName)
        {
            return GetStaticProperty(type, propertyName, null);
        }
        public static object GetStaticProperty(Type type, string propertyName, params object[] index)
        {
            return type.GetProperty(propertyName, flags).GetValue(null, index);
        }
        public static void SetProperty(object obj, string propertyName, object value)
        {
            SetProperty(obj, propertyName, value, null);
        }
        public static void SetProperty(object obj, string propertyName, object value, params object[] index)
        {
            Type type = obj.GetType();
            type.GetProperty(propertyName, flags).SetValue(obj, value, index);
        }
        public static void SetStaticProperty(Type type, string propertyName, object value)
        {
            SetStaticProperty(type, propertyName, value, null);
        }
        public static void SetStaticProperty(Type type, string propertyName, object value, params object[] index)
        {
            type.GetProperty(propertyName, flags).SetValue(null, value, index);
        }
        public static object GetField(object obj, string fieldName)
        {
            Type type = obj.GetType();
            return type.GetField(fieldName, flags).GetValue(obj);
        }
        public static object GetSaticField(Type type, string fieldName)
        {
            return type.GetField(fieldName, flags).GetValue(null);
        }
        public static void SetField(object obj, string fieldName, object value)
        {
            Type type = obj.GetType();
            type.GetField(fieldName, flags).SetValue(obj, value);
        }
        public static void SetStaticField(Type type, string fieldName, object value)
        {
            type.GetField(fieldName, flags).SetValue(null, value);
        }
        private static ConstructorInfo GetConstructor(Type type, Type[] paramTypes)
        {
            return type.GetConstructor(paramTypes);
        }
        public static object CreateInstance(Type type, Type[] paramTypes, params object[] parameters)
        {
            return GetConstructor(type, paramTypes).Invoke(parameters);
        }
        public static object CreateInstance(Type type, params object[] parameters)
        {
            return GetConstructor(type, GetTypesFromObjects(parameters)).Invoke(parameters);
        }
        private static Type[] GetTypesFromObjects(object[] objs)
        {
            Type[] types = new Type[objs.Length];
            for (int i = 0; i < types.Length; i++)
                types[i] = objs[i].GetType();
            return types;
        }
        public static void AddEventHandler(object obj, string eventName, MethodInfo method, object methodOwner)
        {
            EventInfo eventInfo = obj.GetType().GetEvent(eventName, flags);
            Delegate eventDeleg = Delegate.CreateDelegate(eventInfo.EventHandlerType, methodOwner, method);
            eventInfo.AddEventHandler(obj, eventDeleg);
        }
        public static void RemoveEventHandler(object obj, string eventName, MethodInfo method,object methodOwner)
        {
            EventInfo eventInfo = obj.GetType().GetEvent(eventName, flags);
            Delegate eventDeleg = Delegate.CreateDelegate(eventInfo.EventHandlerType, methodOwner, method);
            eventInfo.RemoveEventHandler(obj, eventDeleg);
        }
    }
}

    下面的代码对上面的一些方法进行测试,由于手头只有一个Fetion SDK.dll的文件,所以就拿他开刀了,实现简单的登录,登录后发送一条测试信息到我的手机,为了安全略去了某些信息。

using System;
using System.Collections.Generic;
using System.Text;
using UsefulUtility;
using System.Reflection;
namespace ConsoleApplication1
{
    class Program
    {
        static object sdk;
        static Assembly asm;
        [STAThread]
        static void Main(string[] args)
        {
            // 载入程序集
            asm = Assembly.LoadFrom("Fetion SDK.dll");
            // 获取Fetion SDK的类型
            Type type = Invoker.GetType(asm, "com.hetaoos.FetionSDK.FetionSDK");
            // 实例化sdk
            sdk = Invoker.CreateInstance(type);
            // 获取账号管理的属性
            object accountManager = Invoker.GetProperty(sdk, "AccountManager");
            // 设置用户名和密码
            Invoker.CallMethod(accountManager, "FillUserIdAndPassword", new object[] { "手机号码", "飞信密码", false });
            // 监听事件
            Invoker.AddEventHandler(sdk, "SDK_UserSatusChange", Invoker.GetMethod(typeof(Program), "sdk_SDK_UserSatusChange"), null);
            // 调用登录方法
            Invoker.CallMethod(accountManager, "Login");
        }
        static void Hello()
        {
            Console.WriteLine("hello in Hello");
        }
        static void sdk_SDK_UserSatusChange(object sender, EventArgs e)
        {
            Console.WriteLine(Invoker.GetProperty(e, "NewStatus"));
            Console.WriteLine(Invoker.GetSaticField(Invoker.GetType(asm, "Imps.Client.UserAccountStatus"), "Logon"));
            // 这里用==不好使,要用Equals,不知道为什么
            if (Invoker.GetProperty(e, "NewStatus").Equals(Invoker.GetSaticField(Invoker.GetType(asm, "Imps.Client.UserAccountStatus"), "Logon")))
            {
                Console.WriteLine("hello");
                object contactControl = Invoker.GetProperty(sdk, "ContactControl");
                object sendSMS = Invoker.GetProperty(contactControl, "SendSMS");
                Invoker.CallMethod(sendSMS, "SendSMS", "要发送信息的飞信号或手机号码", "hello, a test");
            }
        }
    }
}

转载请注明出处,本文原始地址:http://www.cnblogs.com/dlutwy/archive/2009/04/28/1445352.html

posted @ 2009-04-28 13:17 小橋流水 阅读(334) 评论(9)  编辑 收藏 网摘 所属分类: 编程语言

  回复  引用  查看    

#1楼 2009-04-28 13:20 | henry      

我常用的
public static T[] GetMethodAttributes<T>(MethodInfo mi, bool inhert) where T: Attribute
{
return (T[]) mi.GetCustomAttributes(typeof(T), inhert);
}
public static T[] GetParemeterAttributes<T>(ParameterInfo pi, bool inhert) where T: Attribute
{
return (T[]) pi.GetCustomAttributes(typeof(T), inhert);
}
public static T[] GetPropertyAttributes<T>(PropertyInfo pi, bool inhert) where T: Attribute
{
return (T[]) pi.GetCustomAttributes(typeof(T), inhert);
}
public static T[] GetTypeAttributes<T>(Type type, bool inhert) where T: Attribute
{
return (T[]) type.GetCustomAttributes(typeof(T), inhert);
}

[FMS]FMS3系列(五):通过FMS实现时时视频聊天(Flash|Flex)

mikel阅读(595)

      本系列的前几篇文章中分别介绍了,连接FMS服务器、建立播放程序以及在线视频录制以及回放等功能的实现。相信看过前面几篇文章的朋友已经对FMS有了一定的认识,并熟悉了常用的编程模式。本文将结合前面几篇文章所出现的技术点,来实现一个时时视频聊天程序。

      通过FMS实现视频时时聊天其实很简单,也就是操作时时流。如果是单向视频聊天,则两端一边一边为发布端一边为订阅端,如果是双向视频聊天,则两边都分别是发布端和订阅端。

      如果从技术实现上来分析,单向视频聊天就是一边发布流另一边播放流,双向视频聊天则是两边都需要提供两个流,一个负责发布流,一个负责播放流。在说专业点就是一个创建流并且发送到服务器的客户端叫发布,一个创建流来接受内容的客户端叫订阅,当同一个客户端同是发布和订阅时,它必须创建两个流,一个是输出流,一个是接受流。

       说了这么多下面看看具体是怎么实现的,要实现视频聊天上面分析过,就是一边发布时时视频流一边播放,这同样离不开连接FMS,代码如下:

private function onPublishClick(evt:MouseEvent):void
{
      nc 
= new NetConnection();
      nc.connect(
"rtmp://localhost/LiveStreams");
      nc.addEventListener(NetStatusEvent.NET_STATUS,onNetStatusHandler);
}

 

       通过点击按扭连接(NetConnection)FMS服务器,然后向FMS发布(publish)视频流,达到视频发布的目的。这 里需要注意一点,在发布方法publish()中后一参数为“live”,表示时时视频流。以live的形式发布的流不会在FMS里生成.fla文件,不 同于“record”录制视频流生成.flv的视频文件。

private function onNetStatusHandler(evt:NetStatusEvent):void
 {
       trace(evt.info.code);
       
if(evt.info.code=="NetConnection.Connect.Success")
       {
           ns
=new NetStream(nc);
           ns.addEventListener(NetStatusEvent.NET_STATUS,onNetStatusHandler);
           ns.client
=new CustomClient();
           ns.attachCamera(cam);
           ns.attachAudio(mic);
           ns.publish(txtInput.text,
"live");
       }
}

 

      实现视频发布的核心技术点就是获取视频、音频数据,分别通过Camera和Microphone的静态方法实现。参考代码:

public function PublishStream():void
{
    btnPublish.label
="发布视频";
    btnPublish.addEventListener(MouseEvent.CLICK,onPublishClick);
            
    
//获取视频和声音,并将视频显示到Flash界面
    cam = Camera.getCamera();
    mic 
= Microphone.getMicrophone();
    video 
= new Video(320,240);
    video.attachCamera(cam);
    video.x
=20;
    video.y
=20;
    addChild(video);
}

 

      通过以上步骤就完成了视频聊天的视频流发布端的开发,完整的示例代码如下:

package
{
    import flash.net.
*;
    import flash.events.
*;
    import flash.display.
*;
    import flash.media.
*;
    import fl.controls.
*;
    
    
public class PublishStream extends Sprite
    {
        
private var video:Video;
        
private var nc:NetConnection;
        
private var ns:NetStream;
        
private var cam:Camera;
        
private var mic:Microphone;
        
        
public function PublishStream():void
        {
            btnPublish.label
="发布视频";
            btnPublish.addEventListener(MouseEvent.CLICK,onPublishClick);
            
            
//获取视频和声音,并将视频显示到Flash界面
            cam = Camera.getCamera();
            mic 
= Microphone.getMicrophone();
            video 
= new Video(320,240);
            video.attachCamera(cam);
            video.x
=20;
            video.y
=20;
            addChild(video);
        }
        
        
private function onPublishClick(evt:MouseEvent):void
        {
            nc 
= new NetConnection();
            nc.connect(
"rtmp://localhost/LiveStreams");
            nc.addEventListener(NetStatusEvent.NET_STATUS,onNetStatusHandler);
        }
        
        
private function onNetStatusHandler(evt:NetStatusEvent):void
        {
            trace(evt.info.code);
            
if(evt.info.code=="NetConnection.Connect.Success")
            {
                ns
=new NetStream(nc);
                ns.addEventListener(NetStatusEvent.NET_STATUS,onNetStatusHandler);
                ns.client
=new CustomClient();
                ns.attachCamera(cam);
                ns.attachAudio(mic);
                ns.publish(txtInput.text,
"live");
            }
        }
    }
}

 

      视频接收端相对发布端更简单,提供一个NetConnetion连接到发布端的FMS,通过NetStream播放时时视频流就完成。代码很简单,基本上都是在本系列前几篇文章中出现过的代码片段整合而成,详细见下代码块:

package
{
    import flash.net.
*;
    import flash.events.
*;
    import flash.display.
*;
    import flash.media.
*;
    
    
public class LiveStream extends Sprite
    {
        
private var video:Video;
        
private var nc:NetConnection;
        
private var ns:NetStream;
        
        
public function LiveStream():void
        {
            nc 
= new NetConnection();
            nc.connect(
"rtmp://localhost/LiveStreams");
            nc.addEventListener(NetStatusEvent.NET_STATUS,onNetStatusHandler);
        }
        
        
private function onNetStatusHandler(evt:NetStatusEvent):void
        {
            
if(evt.info.code=="NetConnection.Connect.Success")
            {
                ns
=new NetStream(nc);
                ns.addEventListener(NetStatusEvent.NET_STATUS,onNetStatusHandler);
                ns.client
=new CustomClient();
                video
=new Video();
                video.attachNetStream(ns);
                ns.play(
"1111");//1111为流的名字,对应于视频流发布端的publish("1111","live").
                addChild(video);
            }
        }
    }
}

 

      OK,到这里视频聊天的两端都完成了,如果需要做双向视频聊天,只需要在每一边多提供一个流就可以了,两端都实现发布视频流和接收视频流数据。

      或许看完文章的朋友回问到CustomClient是那里来的,CustomClient是为了处理元数据的,可以通过元数据向实况视频添加一些格外的属性,本文暂时不讨论,有兴趣的朋友可以查看官方文档了解。

本文示例程序下载:点击下载 (为了节约空间,这里只提供了Flash实现的示例代码,需要Flex的可以留言索取)

版权说明

  本文属原创文章,欢迎转载,其版权归作者和博客园共有。  

  作      者:Beniao

 文章出处:http://beniao.cnblogs.com/  或  http://www.cnblogs.com/

 

[搜索引擎]各搜索引擎搜索结果的获取

mikel阅读(750)

用http的get方法,构造要查询的url,get下来,分析结果页面即可
首先是构造url,以下是一些示例,主要看清楚?号后面的参数所代表的意思即可:
http://www.google.cn/search?num=100&&q=%E5%85%83%E6%90%9C%E7%B4%A2&start=10

http://www.baidu.com/s?wd=%D4%AA%CB%D1%CB%F7&rn=100&pn=10  //第二页pn

http://www.yahoo.cn/s?p=%E5%85%83%E6%90%9C%E7%B4%A2&b=10  //第二页b

http://search.yahoo.com/search?n=100&p=%E5%85%83%E6%90%9C%E7%B4%A2&b=101

http://cnweb.search.live.com/results.aspx?q=%E5%85%83%E6%90%9C%E7%B4%A2&first=51  //第二页first=51

http://p.zhongsou.com/p?w=%D4%AA%CB%D1%CB%F7&b=3  //b=3表示第三页

http://www.soso.com/q?w=%D4%AA%CB%D1%CB%F7&num=20&pg=1 //第一页,每页20个
第二步是解释搜索结果页面:
<meta http-equiv="content-type" content="text/html;charset=gb2312">

Google
搜索结果个数的字符串前缀:约有<b> //获取个数用字符串定位的方式
搜索结果开始的标签:<div id=res> //也可以用字符串定位的方式,要准确就用查找标签定位的方式
 各个搜索结果的开始标签:<div class=g> //字符串定位的方式
 
  搜索结果的url在第一个<a target=_blank class=l>标签里头
  搜索结果的标题在<a></a>的标签之间

  搜索结果的摘要在接下来的<table><tr><td>标签里头直到<b>…<b><br>
  搜索结果的重写的url在<b>…<b><br>之后的<span>标签里头,格式为:url,一个空格,网页大小
  搜索结果的网页快照在接下来的<a class=fl>的标签里头,属性中有url,标签之间有网页快照文字
  接下来还有类似网页等,都在<a class=fl>标签里头

 各个搜索结果的结束标签是</td></tr></table></div>

………………….

相关搜索的开始标签:<p class=e>
在接下来的各个<a></a>标签之间的内容就是相关搜索的内容
直到标签<br clear=all>就可以结束了

 

Baidu
搜索结果个数的字符串前缀:<td align=\"righ,在定位该字符串后,直到</td>,即在这个td标签之内含有的字符串包含相关网页数和用时
搜索结果开始的标签:<DIV id=ScriptDiv></DIV>
 各个搜索结果的开始标签:<table

  搜索结果的url在第一个<a target=_blank class=l>标签里头
  搜索结果的标题在<a></a>的标签之间,以<br>标签结束
  
  搜索结果的摘要以<br>开始直到下一个<br>标签
  
  接下来的一行(<br>换行)的font标签中有搜索结果url的重写,一个空格,网页大小,网页时间
  在接下来会有一些<a>标签如百度快照,直到又一个<br>

 然后搜索结果的结束标签</table>

…………………….

导航条的开始标签:<br clear=all>
导航条的内容在开始标签之后的<div class="p"></div>标签之间
相关搜索在接下来的<div>标签之间的各个<a>标签之内
其他考虑:对于字符串的匹配可以利用kmp,注意到匹配搜索结果各部分的时候所用到的模式字符串的最大前缀字符串最多是一个字符,这样可以避免求取最大前缀字符串从而提高效率;如果要精确地匹配还需要弄两个函数,一个用来构造标签,一个用来读取标签之间的文本。

[图像]图像相似度算法的C#实现及测评

mikel阅读(975)

  近日逛博客的时候偶然发现了一个有关图片相似度的Python算法实现。想着很有意思便搬到C#上来了,给大家看看。

闲言碎语

  才疏学浅,只把计算图像相似度的一个基本算法的基本实现方式给罗列了出来,以至于在最后自己测评的时候也大发感慨,这个算法有点不靠谱。不管怎么样,这个算法有时候还是有用的,所以还是列出来跟大家伙一起分享分享~~

  PS:图像处理这一块博大精深,个人偶尔发现了点东西拿来分享。说的不好的地方,写得太糟的地方,诸位准备扔砖头还望淡定,淡定~~

基本知识介绍

颜色直方图

                颜色直方图是在许多图像检索系统中被广泛采用的颜色特征,它所描述的是不同色彩在整幅图像中所占的比例,而并不关心每种色彩所处的空间位置,即无法描述图像中的对象或物体。颜色直方图特别适用于描述那些难以进行自动分割的图像。

灰度直方图

  灰度直方图是灰度级的函数,它表示图像中具有每种灰度级的像素的个数,反映图像中每种灰度出现的频率。灰度直方图的横坐标是灰度级,纵坐标是该灰度级出现的频率,是图像的最基本的统计特征。

   本文中即是使用灰度直方图来计算图片相似度,关于算法那一块也不赘言了,毕竟图像学图形学,直方图我是门儿都不懂,我也不准备打肿脸充胖子,只想实现一个最基本的算法,然后从最直观的角度看看这个算法的有效性,仅此而已。

 

算法实现

                诸位看官休怪笔者囫囵吞枣,浅尝辄止的学习态度。额毕竟是因兴趣而来,于此方面并无半点基础(当然,除了知道RGB是啥玩意儿——这还幸亏当年计算机图形学的老师是个Super美女,因此多上了几节课的缘故),更谈不上半点造诣,看官莫怪莫怪,且忍住怒气,是走是留,小生不敢有半点阻拦~~

大致步骤如下:

1,  将图像转换成相同大小,以有利于计算出相像的直方图来

2,  计算转化后的灰度直方图

3,  利用XX公式,得到直方图相似度的定量度量

4,  输出这些不知道有用没用的相似度结果数据

代码实现

步骤1 将图像转化成相同大小,我们暂且转化成256 X 256吧。

 

public Bitmap Resize(string imageFile, string newImageFile)

        {

            img = Image.FromFile(imageFile);

            Bitmap imgOutput = new Bitmap(img, 256, 256);

            imgOutput.Save(newImageFile, System.Drawing.Imaging.ImageFormat.Jpeg);

            imgOutput.Dispose();

            return (Bitmap)Image.FromFile(newImageFile);

      }

 

  这部分代码很好懂,imageFile为原始图片的完整路径,newImageFile为强转大小后的256 X 256图片的路径,为了“赛”后可以看到我们转化出来的图片长啥样,所以我就把它保存到了本地了,以至于有了上面略显丑陋的代码。

步骤2,计算图像的直方图

public int[] GetHisogram(Bitmap img)

        {

            BitmapData data = img.LockBits( new System.Drawing.Rectangle( 0 , 0 , img.Width , img.Height ), ImageLockMode.ReadWrite , PixelFormat.Format24bppRgb );

            int[ ] histogram = new int[ 256 ];

            unsafe

            {

                                byte* ptr = ( byte* )data.Scan0;

                                int remain = data.Stride – data.Width * 3;

                                for( int i = 0 ; i < histogram.Length ; i ++ )

                                        histogram[ i ] = 0;

                                for( int i = 0 ; i < data.Height ; i ++ )

                                {

                                        for( int j = 0 ; j < data.Width ; j ++ )

                                        {

                                                int mean = ptr[ 0 ] + ptr[ 1 ] + ptr[ 2 ];

                                                mean /= 3;

                                                histogram[ mean ] ++;

                                                ptr += 3;

                                        }

                                        ptr += remain;

                                }

            }

                        img.UnlockBits( data ); 

            return histogram;

    }

这段就是惊天地泣鬼神的灰度直方图计算方法,里面的弯弯绕还是留给诸位自己去掺和。

步骤3,计算直方图相似度度量

这一步骤的法宝在于这个:

Sim(G,S)= HowTo其中G,S为直方图,N 为颜色空间样点数

为了大家少敲两行字儿,也给出一堆乱七八糟的代码:

 

//计算相减后的绝对值

        private float GetAbs(int firstNum, int secondNum)

        {

            float abs = Math.Abs((float)firstNum – (float)secondNum);

            float result = Math.Max(firstNum, secondNum);

            if (result == 0)

                result = 1;

            return abs / result;

        }

 

        //最终计算结果

        public float GetResult(int[] firstNum, int[] scondNum)

        {

            if (firstNum.Length != scondNum.Length)

            {

                return 0;

            }

            else

            {

                float result = 0;

                int j = firstNum.Length;

                for (int i = 0; i < j; i++)

                {

                    result += 1 – GetAbs(firstNum[i], scondNum[i]);

                    Console.WriteLine(i + "—-" + result);

                }

                return result/j;

            }

    }

 

步骤4,输出

  这个……诸位爱怎么输出就怎么输出吧。直接Console也好,七彩命令行输出也罢,亦或者保存到文本文件中留作纪念啦啦,诸位“好自为之”~~

算法测评

  真对不住大家,忘了跟大家说,我也不是一个专业的算法测评人员,但是作为一个半拉子测试人员免不了手痒痒想要看看这个算法到底有多大能耐,就拿出几张图片出来验验货吧。

以下是算法测评结果。以下部分内容话带调侃,绝无恶意,开开玩笑,娱乐大众~~

 

路人甲

路人乙

图像相似度

恶搞点评

小白

小白

100%

里面什么都没有!?

恭喜你,如果你看不出来这是两张白底图片,那么你还真是小白,因为你连自家人都认不出来啊~~

小黑

小黑

100%

天下乌鸦一般黑,这个算法在这一点上立场还算坚定,表现不错~

Win7

win7

100%

碰到Win7也不动心,意志坚定地给出了100%的正确答案。

 

这算法比我意志坚定多了,我可是win7刚出来个7000就装了,还一直用到现在,不过确实好用~~

我

你

88.84%

明明很不一样的“我”跟“你”摆在那里,怎么就相似度这么高咧??

 

难道,“我”,“你”都认不出来??

 

哦,我忘了,这两张图片的大背景是一样的,难怪……

win7

Mac

16.08%

MSApple这么水火不相容?

【均使用默认桌面~~

Rose

Jack

50.64%

终于了解了JackRose不能在一起的真正原因:

不是爱的不够深,也不是泰坦尼克号沉了,用老妈的话说“没有‘夫妻’相”

—— 还是老妈这个过来人老道~~

小黑

小白

99.21%

哇,太不可思议了,竟然是这样。

这算法这样“黑”“白”不分??

 

我得向JackRose的忠实Fans道歉了,上面的话是一时失言~~祝他们俩白头偕老,下辈子千万别做船了,坐船也不出海,出海也不去北极,……

 

 

  经过我略显玩世不恭的测评活动,说实话,我对这个算法是相当的失望,尤其是最后一次对比中的结果,目前情绪低落中。这倒不是说这算法的一无是处,应该是我或者某些前辈用错了地方,个人觉得算法使用的局限性太大,也或许是我的期望值太高了吧。

后记

  开始看到这玩意儿的时候觉得这玩意儿很简单啊,可是一想不对劲,没有这么容易的事情,要不GoogleMS这些大牛们做了这么久还没有像样的玩意儿出来。果不其然,为了多了解一点相关的内容,我不得不Google了一下,觉得那些术语完全不知所云,看不懂啊;看来我得祭出我一般不使用的大杀器了——百度一搜。嘿,还真找出来了一堆东西,比Google上面的看起来容易多了,可是打开链接进去瞅瞅,发现还是非我当前能力之所及。没学到东西,但是好歹还是了解了一点皮毛上的皮毛。

全文完

  诸位看官若觉得讲得没有意义,浪费了你的时间,那就权当作冷笑话听听缓解一下紧张的神经~~

参考链接:

http://blog.csdn.net/lanphaday/archive/2008/04/24/2325027.aspx

http://www.baidu.com

http://www.google.com

[SQL]一步一步优化SQL语句(二):物理查询处理

mikel阅读(1091)

我在上一篇一步一步优化SQL语句(一):逻辑查询的各个阶段中详细介绍了SQL server中逻辑查询的各个阶段,几位园子的朋友读了以后发出了这样的疑问:
select *
from tab1, tab2
where tab1.id = tab2.id and tab1.col1 = 123 and tab2.col1 = 'abc'
照你所述的执行顺序,先要tab1和tab2进行笛卡尔乘积,再按照tab1.col1 = 123 and tab2.col1 = 'abc'进行筛选。这样的话,效率岂不是很低,数据库有这么愚蠢吗?
我想很多人都会有这个疑问,包括我在最初学习的时候也提出过这样的问题。那么,我的这篇文章就结合这个问题来讨论一下SQLServer的物理查询处理。 首先我们必须明白逻辑处理和物理处理和区别,逻辑处理是指执行一个查询应该产生什么样的结果,那么逻辑查询的各个阶段就是这个查询从逻辑上执行的先后顺 序,依照这个先后顺序就能得到正确的结果,正如我们做四则混合运算一样,先乘除后加减才能得到正确结果。所以说逻辑查询只关心产生一个我们期望的、正确的 结果,它并不关心产生这个结果需要多少的资源消耗。而物理处理就是怎么得到这个结果,这个时候才会考虑性能问题。下面我们就讨论下怎么执行这个物理处理 的。

当一个查询到达数据库引擎的时候,数据库引擎需要做的是执行这个查询的查询计划,那么这个时候就存在两种情况,一种可能是这个查询的查询计划已经在 缓存中,这种情况就直接执行这个查询计划。另外一种情况就是在缓存中找不到该查询的查询计划。没有怎么办?生成一个!怎么生成?
执行计划是在编译阶段生成的,编译需要经过三个步骤:分析、代数化(algebrization)、查询优化,看见没有这里的查询优化过程就能解决上面的朋友提出的先笛卡尔集在筛选造成性能低的问题。下面我就对这三个步骤作一个介绍。

第一步:分析是检查语法并把SQL批处理转化成分析树的过程,如select * t1 where id in(1,2,3,4,5,6,7)在被分析树分析后就展开成了select * t1 where id=1 or id=2 or id=3 or id=4 or id=5 or id=6 or id=7 ,除此之外还有检查语法是否正确的功能。

第二步:接下的过程是代数化(algebrization),这个阶段使用SQLServer 2005的新组件algebrizer,algebrizer组件的主要功能是绑定,因此代数化过程通常称为绑定。这个阶段是将第一步的分析树作为输入, 生成被称为查询处理器树的输出,用于查询优化。其实这个阶段主要做几个事情,一:运算符平展,简单的讲就是把二元运算符组合成N元运算符,这里必须给出一 个示例才能很好的解释这个二元转换成N元如第一步所示in操作展开成了一连串的or运算符,而分析器认为这些or都是二元的,也就是说它认为第一个or 的左孩子是id=1,右孩子是 (id=2 or id=3 or id=4 or id=5 or id=6 or id=7 )这个表达式,而右孩子又被认为是二元的,如此一来就必须进行一个递归过程。而运算符平展过程则将这种二元运算组合成n元运算符,就避免了递归的过程。 二:名称解析,这个过程其实就是检查这个查询中出现的表或者是表的列是不是在数据库中真实存在。以及在该查询过程中是不是可见的。三:类型派生,有点抽 象,举个例子就能理解了,比如union查询吧,union左右两边查询结果对应位置的数据类型应该是一致的。四:聚合绑定和组分绑定,执行完这个步骤后 查询处理器树便生成了。

第三步:查询优化,这个过程由查询优化器组件来完成的。查询中应该以何种顺序访问表,使用哪种方法和使用哪个索引,应该由哪个联接算法等都是由查询 优化器组件来决定的,但是这个决定也不是随意的,它必须满足的前提条件是保证最后得到的结果集必须是正确的,也就是说该结果集必须遵循逻辑处理的各个阶段 所得到的结果集相同。优化器会尝试该查询的许多变体,一查找成本最低的计划。如果优化器分析该查询的元数据得知只有一个可执行的计划,那么它就不会再尝试 寻求更好的计划,这个步骤叫做细微计划优化。如果没有找到细微计划优化,SQLServer将执行一些简化,简化就是对自身语法作一些转换,比如在联接前 计算表的where筛选器,如前一篇描述的,逻辑查询中where筛选总是在联接之后计算,但是先计算where筛选器在联接同样能得到的正确的结果,而 这样的效率往往是更高的,所以在物理处理中where往往在join前执行的,开篇提到的那个问题只是读者未理解逻辑处理和物理处理的差别而已。

到此为止,物理处理的各个步骤也做了一个简要的叙述,总结下,无论是存储过程还是即席查询都是执行的一个查询计划的副本,如果这个查询计划不存在的 话就必须经过编译生成一个执行计划,在编译阶段必须经过分析,绑定(代数化),查询优化这些过程,最终得到我们需要查找的结果。关于查询优化组件具体是怎 么优化查询处理器树的,我会在以后的篇幅作详细介绍。

[C#]ASP.NET MVC + ADO.NET EF 项目实战(一):应用程序布局设计

mikel阅读(736)

ASP.NET MVC + ADO.NET EF 项目实战(一):应用程序布局设计

什么叫上下文?

在你设计一个方法的时候,无法直接从方法参数或实例成员(字段或属性)获得的所有信息都是上下文。例如:

  • 当前用户是谁?
  • 刚才提供操作的数据库连接实例从哪里拿到?
  • 这个方法从哪个 View 或者哪个 Controller 调用的?

当然,在方法体中获得上下文最终还是要靠方法参数或实例成员。

在MVC中有大量的上下文信息,例如:

  • ControllerContext
  • ViewContext
  • ModelBindingContext
  • ExceptionContext
  • ActionExcutingContext
  • ActionExcutedContext
  • AuthorizationContext
  • ResultExcutingContext
  • ResultExcutedContext

这些上下文通过单一的参数提供了丰富的运行时信息。

实体上下文放到哪里?

除了MVC的上下文外,还有一个重要的上下文就是 ADO.NET EF的实体上下文,通常派生自System.Data.Objects.ObjectContext,都是由IDE自动生成的。这个上下文承载了数据库连 接,需要通过IDisposable来释放连接。多数情况下,我们这样使用:

using(MyEntities context = new MyEntities())
{
…… 在这里写入代码
}

如果在一次页面生命周期内只使用一次实体上下文这样处理是非常合适的,但是事实上不都是这样。更多的时候可能需要临时对实体进行一个小的访问,例如获得一个当前用户的显示名,通过这种方式访问就代价太大了。

我们知道,这个上下文可以存放到HttpContext里。在HttpContext的所有容器中,只有Items是最合适的,因为这个属性的存续 期在后台页面对象释放后就结束了。当然,被释放时也不会执行IDisposable的Dispose方法。我们仍然需要在Global.asax中捕捉 EndRequest事件。但是奇妙的是:在ASP.NET MVC Application中不能使用event方式来捕捉,只能手工写Application_EndRequest方法

什么是一次Model、二次Model和Form Model?

Model一共分为三种:

  • 直接数据库实体映射实例,如Product(产品)
  • 为View的呈现提供服务的包装对象,如ProductInfo(产品信息)
  • 为Post回传提供服务的包装对象,如ProductForm(产品属性值)

第一种类型Model的特点是非常浓缩,几乎没有冗余,通过复杂的关系进行组合,通常需要通过多个不同类型的实例进行组合来表达一个完整的有意义的 场景。例如,一个产品信息可能包含产品名称、产品类别、该产品所有的规格型号以及每种规格型号的参数、单价等。虽然ADO.NET EF提供了获取组合属性的能力,但不能处理多层次,并且不能对加载过程进行控制。所以,需要专门定义一些Model对这一组Model进行包装。如果把原 始的模型称做“一次Model”,则可以把这个包装对象称做“二次Model”。

页面上收集到的Form信息,通过三种方式传递到Controller(以登录为例):

  • 每个信息项一个参数:public ActionResult Login(string userName, string password){…}
  • 一个单一的名值对参数:public ActionResult Login(FormCollection formCollection){…}
  • 一个单一的包装对象:public ActionResult Login(LoginInfo info){…}

第一种方式不利于重构。当需要加入一个参数时,必须修改Action的签名。而且也无法令Controller把值传递到View。第二种方式不利 于设计时纠错,因为FormCollection中的值不是强类型的。所以,我们通常都会采用第三种方式。虽然ADO.NET EF对象可以直接作为Form Model,并且有BindAttribute对属性与Form值进行定制化的绑定,但是不够灵活,如果一个Form组合跨多个一次Model类型,则根 本无法处理。所以我们有必要专门定义一个Model给View使用。我们不妨称之为“Form Model”。

业务逻辑放到什么地方?

MVC是一种“古老”的设计模式,提供了非常自然的分层方式,这也是为什么利于单元测试的原因。除了MVC这些“主层”以外,BLL可以算是一个“亚层”。那么,我们把BLL放到什么地方最合适?

BLL需要完全可见Model层,同时也需要一些上下文信息。例如,我们至少从我们刚才描述的论题中发现,需要从HttpContext的 Items中获得实体上下文。有些时候,我们还需要将用户的一些登录信息缓存到HttpContext中,如果用户的登录信息非常复杂的话,仅仅依靠 HttpContext.User.Identity.Name每次去抓取未必很合算。我的习惯是把和这个用户相关的信息组合到一个大的Model对象 中,并把这个对象的实例 存放到HttpContext.Cache中。如果有任何变化,释放这个Cache项即可。

所以,对于业务逻辑的位置你可以有两个选择:

  • 放到 Model 下,再建立一个“上下文提供器接口”,由 Model 借助上下文来独立处理。
  • 放到 Controller 下,直接使用 Controller 提供的上下文来进行处理。

第一种方式不依赖Controller,解耦彻底,非常灵活,更易于测试。但是需要付出一定的成本,调用栈会稍深一点,还需要劳神处理到 Controller与BLLContext间的关系。第二种方式解耦不够彻底,但非常简捷,比较适合 Controller 与 Model 不必彻底解耦的小型项目。有意思的是:ASP.NET MVC Application模板所生成的AccountController采用的就是第二种方式。

ADO.NET EF仅影响ASP.NET MVC的Model层。在Model层中除了EDMX自动生成的一次Model外,我们还需要建立大量的二次Model和Form Model。当然,从提升内聚度考虑,所有的业务逻辑方法都在这些Model中定义,特别是,可以利用partial类和扩展方法这两种手段加入业务逻 辑。

[SQL]一步一步优化SQL语句(一):逻辑查询的各个阶段

mikel阅读(949)

大家好,我是忆然,前段时间我在学习ItZik Ben-Gan、Lubor Kollar、Dejan Sarka所著的《SQL Server

2005 技术内幕:T-SQL查询》一书,在此我把一些学习的心得跟大家分享

在查询中逻辑查询和物理查询有着本质的区别,SQL不同于其它编程的最明显的特征就是处理代码的顺序,

虽然总是最先写Select 但是几乎总在最后执行,那到底是怎么一个执行顺序呢

作者给出了如下的sql查询语句执行顺序

(8) select (9) distinct (11) <top_specification> <select_list>

(1)from <left_table>

(3) <join_type> join <right_table>

(2) on <join _condition>

(4) where <where_condition>

(5)group by <group_by_list>

(6) with {cube|rollup}

(7)having(having_condition)

(10) order by <order_by_condition>

从这个顺序中我们不难发现,所有的 查询语句都是从select开始执行的,在执行过程中,每个步骤都会为

下一个步骤生成一个虚拟表,这个虚拟表将作为下一个执行步骤的输入。

 

第一步:首先对from子句中的前两个表执行一个笛卡尔乘积,此时生成虚拟表 vt1

第二步:接下来便是应用on筛选器,on 中的逻辑表达式将应用到 vt1 中的各个行,筛选出满足on逻辑表

达式的行,生成虚拟表 vt2

第三步:如果是outer join 那么这一步就将添加外部行,left outer jion 就把左表在第二步中过滤的添

加进来,如果是right outer join 那么就将右表在第二步中过滤掉的行添加进来,这样生成虚拟表 vt3

第四步:如果 from 子句中多余两个表,那么就将vt3和第三个表连接,执行笛卡尔乘积。生成虚拟表,该

过程就是一个重复1-3的步骤。

第五步:应用where筛选器,对上一步生产的虚拟表引用where筛选器,生成虚拟表vt4,在这有个比较重要

的细节不得不不说下,对于包含outer join的子句查询,就有一个让人感到困惑的问题,到底在on筛选器

还是用where筛选器指定逻辑表达式呢?on和where的最大区别在于,如果在on应用逻辑表达式那么在第三

步outer join中还可以把移除的行再次添加回来,而where的移除的最终的。举个简单的例子,有一个学生

表(班级,姓名)和一个成绩表(姓名,成绩),我现在需要返回一个x班级的全体同学的成绩,但是这个班级

有几个学生缺考,也就是说在成绩表中没有记录。为了得到我们预期的结果我们就需要在on子句指定学生

和成绩表的关系(学生.姓名=成绩.姓名)那么我们是否发现在执行第二步的时候,对于没有参加考试的学

生就不会再vt2中出现,应为他们被on的逻辑表达式过滤掉了,但是我们用left outer join就可以把左表(

学生)中没有参加考试的学生找回来,应为我们想返回的是x班级的所有学生,如果在on中应用学生.班级

='x'的话,那么在left outer join 中就会将不是x班级的学生找回来,所以只能在where筛选器器重用用

学生.班级='x' 应为它的过滤是最终的。

第六步:group by 子句将<group_by_condition>中的唯一的值组合成为一组,得到虚拟表vt5。如果应用

了group by,那么后面的所有步骤都只能得到的vt5的列或者是聚合函数(count、sum、avg等)。原因在

于最终的结果集中只为每个组包含一行。

第七步:应用cube或者rollup选项,为vt5生成超组,生成vt6.

第八步:应用having筛选器,生成vt7。having筛选器是第一个也是为唯一一个应用到已分组数据的筛选器

第九步:处理select列表。将vt7中的在select中出现的列筛选出来。生成vt8.

第十步:应用distinct子句,vt8中移除相同的行,生成vt9。事实上如果应用了group by子句那么

distinct是多余的,原因同样在于,分组的时候是将列中唯一的值分成一组,同时只为每一组返回一行记

录,那么所以的记录都将是不相同的。

第十一步:应用order by子句。按照order_by_condition排序vt9,此时返回的一个游标,而不是虚拟表。

sql是基于集合的理论的,集合不会预先对他的行排序,它只是成员的逻辑集合,成员的顺序是无关紧要的

。对表进行排序的查询可以返回一个对象,这个对象包含特定的物理顺序的逻辑组织。这个对象就叫游标

。正因为返回值是游标,那么使用order by 子句查询不能应用于表表达式。排序是很需要成本的,除非你

必须要排序,否则最好不要指定order by,最后,在这一步中是第一个也是唯一一个可以使用select列表

中别名的步骤。

第十二步:应用top选项。此时才返回结果给请求者即用户。

带出为止我们将一个sql查询语句真正的执行过程梳理了一遍,对于使用查询语句多年的我来说,无疑对以

前的不少问题得出了解答。希望你也能从中受益。我将在后面介绍SQLServer 2005中新加入的逻辑处理阶

段。