nopcommerce中文网

nopcommerce是国外asp.net领域一个高质量的b2c开源项目,基于EntityFramework和MVC开发,QQ群1:75272942(2000人超级群,已满) QQ群2:640322459

导航 - 搜索

Asp.net MVC 4 异步方法

今天我们来看一下,同样功能在 Asp.net MVC 4 下的实现,基于.net framework 4.5 下的async支持,让我们的代码更加简单,看下面片断代码名叫Index的Action方法: 

        public async Task<ActionResult> IndexAsync()
        {
            var cnblogsTask = GetStringAsync("http://www.cnblogs.com");
            var myblogTask = GetStringAsync("http://www.cnblogs.com/wintersun");
 
            // Asynchronously wait for them all to complete.
            await Task.WhenAll(cnblogsTask, myblogTask);
 
            Operations translations = new Operations() { 
                FirstOperation = cnblogsTask.Result, SecondOperation = myblogTask.Result };
 
            return View(translations);
        }

 

        private static async Task<string> GetStringAsync(string uri
            , CancellationToken cancelToken = default(CancellationToken))
        {
            using (HttpClient httpClient = new HttpClient())
            {
                var response = await httpClient.GetAsync(uri, cancelToken);
                return (await response.Content.ReadAsStringAsync());
            }
        }


上面的代码我们实现多个Task并行异步,注意asyncawait关键字,在.NET 4.5 与 Visual Studio 2012下可用。你只可以使用await关键字同时标注了async的方法。使用异法的HttpClient来替代WebClient类,await关键字运用到HttpClient的异步方法上。使用Task.WhenAll等待所有任务结束。我们知道TPL中还提供了CancellationToken,MVC框架中也提供了AsyncTimeout特性,看面下面示例代码: 

        [AsyncTimeout(100)]
        [HandleError(ExceptionType = typeof(TimeoutException),View = "Error")]
        public async Task<ActionResult> IndexCancleAsync()
        {
            var cancellationToken = new CancellationToken(false);
            var cnblogsTask = GetStringAsync("http://www.cnblogs.com", cancellationToken);
            var myblogTask = GetStringAsync("http://www.cnblogs.com/wintersun", cancellationToken);
 
            await Task.WhenAll(cnblogsTask, myblogTask);
 
            Operations translations = new Operations()
            {
                FirstOperation = cnblogsTask.Result,
                SecondOperation = myblogTask.Result
            };
 
            return View(translations);
        }


我们设置异步超时为100毫秒,并且我们可以传递CancellationToken的参数给具体的Task。 最后把结果返回给View,实际你可以自行Debug看其中过程。

希望对您Web开发有帮助。 

ASP.NET MVC 3和Razor中的@helper 语法

  ASP.NET MVC 3支持一项名为“Razor”的新视图引擎选项(除了继续支持/加强现有的.aspx视图引擎外)。当编写一个视图模板时,Razor将所需的字符和击键数减少到最小,并保证一个快速、通畅的编码工作流。

  与大部分模板的语法不同,在Razor的帮助下,您不需要中断代码编写,仅仅为了在HTML中标注服务器端代码块的开始和结束。代码分析器足够聪明,它能够从你的代码里推断出是否为服务器端代码。这种更加简洁、富有表现力的语法更加干净,输入也更快速,有趣。

  今天的博文涵盖了Razor的一项很多人都不知道的功能——利用@helper语法定义可重用的帮助器方法。

  简单的 @helper 方法应用场景

  Razor中的@helper语法让您能够轻松创建可重用的帮助器方法,此方法可以在您的视图模板中封装输出功能。他们使代码能更好地重用,也使代码更具有可读性。让我们看一个超级简单的应用场景,它展示了@helper语法是怎样被使用的。

  在我们定义@helper方法之前的代码

  让我们看一个简单的产品列表应用场景。在此场景中,我们列出产品明细并输出产品的价格或是单词“免费!”——如果这个产品不花费任何成本的话:

  以上代码非常直截了当,而且Razor的语法使得在HTML里能简单地集成服务器端C#代码。

  然而,一个有点混乱的地方是价格的if/else逻辑。我们可能在站点的其他位置输出价格(或者在同一页面上),而复制以上逻辑很容易出错且难以维护。类似的应用场景是使用@helper语法提取和重构成为帮助器方法的首选考虑。

  使用@helper语法重构以上样例

  让我们提取价格输出逻辑,并将其封装在一个我们将命名为“DisplayPrice”的帮助器方法内。我们可以通过重写以下代码样例来实现此操作:

  我们已经使用上述@helper语法来定义名为“DisplayPrice”的可重用帮助器方法。就像标准C#/VB方法一样,它可以包含任意数量的参数(您也可以定义参数为空或可选参数)。不过,与标准C#/VB方法不同的是,@helper方法可以同时包含内容和代码并支持其中的完整Razor语法——这使得定义和封装呈现/格式化帮助器方法变得非常简单。

  您可以像调用一个标准的C#或VB方法一样,调用@helper方法:

  当调用该方法时,Visual Studio会提供智能感知代码:

  在多视图模式中重用@helper

  在上面的实例中,我们在相同的视图模板中将@helper方法定义为调用它的代码。或者,我们可以将@helper方法定义在视图模板外,并保证其在项目的所有视图模板中可重复使用。

  您可以在.cshtml/.vbhtml保存我们的@helper方法,并把这个文件放在项目根目录下创建的\App_Code目录下例如,我在\App_Code文件夹中创建了一个“ScottGu.cshtml”文件,并且在文件中定义了2个单独的帮助器方法(在每个文件中您可以有任意数量的帮助器方法):

  一旦我们的帮助器定义在应用程序级别,我们就可以在应用程序的任何视图模板中使用它们。

  在上面的\App_Code文件夹中的ScottGu.cshtml会逻辑编译为一个称为“ScottGu”的类。这个类中包含了“DisplayPrice” 和 “AnotherHelper”的静态成员。我们可以使用以下代码重写前面的示例来调用它:

  当像如下方法调用应用程序级别帮助器时,Visual Studio将会提供智能感知代码:

  5月15日更新:有一些人指出的一个问题是,当一个@helper保存在\app_code目录中时,默认情况下您不能访问其中的ASP.NET MVC Html帮助器方法。(例如Html.ActionLink(), Html.TextBox()等等)。而当它们定义在与视图相同的文件夹中,您是可以访问内置HTML帮助器方法的。当帮助器位于\app_code目录下时,确实当下是不支持内置HTML帮助器方法的访问的——我们将在下次发布中添加此功能。Paul Stovall有一个很好的帮助器类,您可以同时访问和使用它和您在\app_code目录下定义的@helper方法中的内置Html方法。请从这里了解更多关于如何使用的信息。

  总结

  Razor的@helper语法提供了一种简便的方法来将呈现功能封装到帮助方法中去。您可以在单个视图模板或整个项目的所有视图模板中重用它。

  您可以使用此功能来编写更加干净、更易维护的代码。

转载:想爱容易,相处难:当ASP.NET MVC爱上IoC

也许你会问ASP.NET MVC为什么会爱上IoC?

  相爱的理由常常很简单,就像一首歌中所唱——“只为相遇那一个眼神”。

  而ASP.NET MVC爱上IoC只为IoC能实现MVC控制器的依赖注入。

  下面是博客园招聘频道(job.cnblogs.com)所用的一个MVC控制器:

复制代码
public class EnterpriseController
{
protected IJobService _jobService;
protected IEnterpriseService _enterpriseService;

#region Constructors
public EnterpriseController(IJobService jobService,
IEnterpriseService enterpriseService)
{
_jobService
= jobService;
_enterpriseService
= enterpriseService;
}
#endregion
}
复制代码

  如上面的代码所示,有了IoC进行依赖注入,就不需要在构造函数中专门创建对应于_jobService与_enterpriseService的实例。IoC容器会在运行时自动创建IJobService与IEnterpriseService的实例,并传递给EnterpriseController的构造函数。

  就因为这一点,MVC就爱上了IoC。爱就这么简单。

  但是相爱容易,相处难。。。相处的过程中总会遇到各种各样的问题。。。所以幸福来自于你是否能努力解决这些问题。

  代码世界也一样,当我们让MVC与IoC相处时,就遇到了问题。这里我们以IoC容器Unity为例,说明一下我们遇到的问题与解决方法。

  要想实现Controller的依赖注入,就需要让IoC容器接管Controller的创建,而ASP.NET MVC 3中提供的IDependencyResolver接口就为实现这个提供了可能。所以,我们首先创建一个实现IDependencyResolver接口的UnityDependencyResolver类,代码如下:

复制代码
public class UnityDependencyResolver : IDependencyResolver
{
IUnityContainer container;

public UnityDependencyResolver(IUnityContainer container)
{
this.container = container;
}

public object GetService(Type serviceType)
{
return container.Resolve(serviceType);
}

public IEnumerable<object> GetServices(Type serviceType)
{
return container.ResolveAll(serviceType);
}
}
复制代码

  UnityDependencyResolver的作用就是调用IoC容器(这里是Unity)解析相应类型的实例。创建了UnityDependencyResolver,我们还需要告诉MVC用它进行解析。在Global.asax的Application_Start()方法中添加如下代码:

protected void Application_Start()
{
IUnityContainer container
= new UnityContainer();
DependencyResolver.SetResolver(
new UnityDependencyResolver(container));
}

  我们运行一下程序试试,出现下面的错误提示:

The current type, System.Web.Mvc.IControllerFactory, is an interface and cannot be constructed. Are you missing a type mapping?

  从上面的错误信息可以分析出,错误是发生在调用UnityDependencyResolver.GetService方法时。ASP.NET MVC在运行的时候需要得到IControllerFactory的实现实例,然后用它去创建相应的控制器实例。如果不用IoC容器,MVC默认会创建DefaultControllerFactory的实例。现在用了IoC,MVC找不到IControllerFactory的实现实例(我们根本没有注册嘛),所以出现上面的错误。

  为了解决这个问题,我们注册一下DefaultControllerFactory:

container.RegisterType<IControllerFactory, DefaultControllerFactory>();

  继续运行程序,又出现新的错误:

The current type, System.Web.Mvc.IControllerActivator, is an interface and cannot be constructed. Are you missing a type mapping?

  找不到IControllerActivator的实现实例,看来,创建Controller还需要这个东东。查看MVC的源代码发现IControllerActivator的默认实现是DefaultControllerActivator,但郁闷的是它竟然是private class,无法注册它。别无选择,只能自己实现IControllerActivator,名叫CustomControllerActivator,代码如下:

复制代码
public class CustomControllerActivator : IControllerActivator
{
IController IControllerActivator.Create(
System.Web.Routing.RequestContext requestContext,
Type controllerType)
{
return DependencyResolver.Current
.GetService(controllerType)
as IController;
}
}
复制代码

  继续运行,又出现新的错误:

The current type, System.Web.Mvc.IViewPageActivator, is an interface and cannot be constructed. Are you missing a type mapping?

  天哪!难道MVC中的所有接口都要注册一下。。。

  这时,脑子里突然闪出一个指示牌:

  于是,脚踩刹车,打了一把方向盘,驶上了另一条道 —— 如果IoC容器中没有注册,不引发异常,而是返回null,让MVC用自己的方式去处理。

  修改UnityDependencyResolver的GetService方法:

复制代码
public object GetService(Type serviceType)
{
if (!this.container.IsRegistered(serviceType))
{
return null;
}
return container.Resolve(serviceType);
}
复制代码

  并取消之前在IoC容器中对DefaultControllerFactory与CustomControllerActivator的注册。

  继续运行,成功!虽然成功,但停车一看,原来兜了一个圈子,又回到了出发的地方。一切还是交由MVC处理,IoC容器形同虚设,Controller的依赖注入无法实现。如果这时访问想依赖注入的Controller(构造函数带有参数),会出现下面的错误提示:

No parameterless constructor defined for this object.

  虽然回到原地,看上去没有前进一步,但实际上你已离目标更近一些(积累了经验,下次前进速度会更快)。就像你追一个女孩子,费尽心思,却被拒绝,看似你的一切努力付之流水,实际上她的心门已经有点松动。。。这时,你要有一种锲而不舍的精神,把失落感扔到九霄云外,然后继续努力,坚信“精诚所至,金石为开”。解决技术问题也是同样道理。

  重头再来!阅读MVC的源代码,了解MVC的请求处理过程,看看MVC是在什么地方创建Controller的实例的,然后看有没有办法让IoC容器来接管。

  MvcHandler.BeginProcessRequest->MvcHandler.ProcessRequestInit,呵呵,找到:  

factory = ControllerBuilder.GetControllerFactory();
controller
= factory.CreateController(RequestContext, controllerName);

  上面的代码中,factory的类型是IControllerFactory,ControllerBuilder.GetControllerFactory()的作用是获取IControllerFactory的实现实例,而实际是通过调用IDependencyResolver接口得到的(我们之前实现的UnityDependencyResolver接管了IDependencyResolver接口)。但我们没有在IoC容器中注册IControllerFactory,实际是由MVC返回IControllerFactory的默认实现DefaultControllerFactory。从上面的代码还可以看出,Controller实例的创建是通过调用IControllerFactory.CreateController()方法,所以,我们要在DefaultControllerFactory.CreateController()方法中寻找线索,对应代码如下:

public virtual IController CreateController(RequestContext requestContext, string controllerName) {
Type controllerType
= GetControllerType(requestContext, controllerName);
IController controller
= GetControllerInstance(requestContext, controllerType);
return controller;
}

  CreateController()又调用了GetControllerInstance()得到Controller的实例,进一步查看其代码:

protected internal virtual IController GetControllerInstance(RequestContext requestContext, Type controllerType) {
return ControllerActivator.Create(requestContext, controllerType);
}

  ControllerActivator的类型是IControllerActivator,之前也提到过,IControllerActivator的默认实现是DefaultControllerActivator,由此可以看出,Controller实例的创建是由DefaultControllerActivator完成的。我们要实现依赖注入,就要由IoC容器来接管。

  那如何来接管呢?——重载DefaultControllerFactory的CreateController方法,将创建Controller实例的工作转交给IoC容器,代码如下:

复制代码
public class UnityControllerFactory : DefaultControllerFactory
{
IUnityContainer container;
public UnityControllerFactory(IUnityContainer container)
{
this.container = container;
}

protected override IController GetControllerInstance(RequestContext reqContext,
Type controllerType)
{
return container.Resolve(controllerType) as IController;
}
}
复制代码

  然后在IoC容器中注册一下UnityControllerFactory:

container.RegisterType<IControllerFactory, UnityControllerFactory>();

  然后,运行程序。。。功夫不负有心人,依赖注入成功,问题解决!从此,MVC与IoC过上了幸福的生活。

  小结

  要实现ASP.NET MVC控制器的依赖注入,我们需要:

  1. 实现IDependencyResolver接口并通过DependencyResolver.SetResolver告知MVC,将部分类型实例解析工作交由IoC容器来处理;

  2. 继承DefaultControllerFactory,重载GetControllerInstance方法,并通过IoC容器将之注册为IControllerFactory的实现。

原文:http://www.cnblogs.com/dudu/archive/2011/08/15/mvc_ioc_dependency_injection.html

  完整示例代码下载

发布mvc报错:403.14-Forbidden Web 服务器被配置为不列出此目录的内容

有两个地方需要配置:

1.web.config中的节点:

<system.webServer>
    <validation validateIntegratedModeConfiguration="false" />
    <modules runAllManagedModulesForAllRequests="true" />
</system.webServer>

需要在modules配置中添加属性runAllManagedModulesForAllRequests

 

2.如果上一个步骤不能够凑效,则需要“添加脚本映射”

  1. 打开IIS的”处理程序映射设置“,在右边的操作栏下有 ”添加脚本映射“
  2. 请求路径:*
  3. 可执行文件:C:\Windows\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll

 

如果完成这两个步骤还不行,那就重新注册一下.net framework试试,当然这一步骤也可以排在第一位。

32位的Windows:
---------------------------------------------------------------------------
1. 运行->cmd 

2. cd  C:\Windows\Microsoft.NET\Framework\v4.0.30319

3. aspnet_regiis.exe -i

 

64位的Windows:
---------------------------------------------------------------------------
1. 运行->cmd 

2. cd  C:\Windows\Microsoft.NET\Framework64\v4.0.30319

3. aspnet_regiis.exe -i

 

参考链接:

iis7 发布mvc3 遇到的HTTP错误 403.14-Forbidden Web 服务器被配置为不列出此目录的内容及Login on failed for "IIS APPPOOL\ASP.NET v4.0"问题

注册asp.net 4.0 到iis

【ASP.Net MVC3 】使用Unity 实现依赖注入

什么是Unity?

Unity是一个轻量级的可扩展的依赖注入容器,支持构造函数,属性和方法调用注入。Unity可以处理那些从事基于组件的软件工程的开发人员所面对的问题。构建一个成功应用程序的关键是实现非常松散的耦合设计。松散耦合的应用程序更灵活,更易于维护。这样的程序也更容易在开发期间进行测试。你可以模拟对象,具有较强的具体依赖关系的垫片(轻量级模拟实现),如数据库连接,网络连接,ERP连接,和丰富的用户界面组件。例如,处理客户信息的对象可能依赖于其他对象访问的数据存储,验证信息,并检查该用户是否被授权执行更新。依赖注入技术,可确保客户类正确实例化和填充所有这些对象,尤其是在依赖可能是抽象的 。

如何得到Unity?

您可以访问http://unity.codeplex.com/releases得到最新版本的Unity现在。当然,如果您在您的visual studio 中安装了Nuget 包管理器,你可以直接在Nuget中获取到最新版本的Unity。

API

 

UnityContainer.RegisterType<ITFrom,TTO>();

UnityContainer.RegisterType< ITFrom, TTO >();

UnityContainer.RegisterType< ITFrom, TTO >("keyName");

IEnumerable<T> databases = UnityContainer.ResolveAll<T>();

IT instance = UnityContainer.Resolve<IT>();

T instance = UnityContainer.Resolve<T>("keyName");

UnitContainer.RegisterInstance<T>("keyName",new T());

UnityContainer.BuildUp(existingInstance);

IUnityContainer childContainer1 = parentContainer.CreateChildContainer();

代码举例

在开始之前我们要先做一些准备工作。首先创建一个控制台应用程序。使用Nuget 添加Unity到当前项目中。我们可以发现,dll引用中多了3个dll:Microsoft.Practices.ServiceLocation, Microsoft.Practices.Unity和Microsoft.Practices.Configuation。

示例1:根据接口依赖创建类

上边简单介绍了Unity的API。如果在没有注册的情况下Resolve一个类型会发生什么呢?

假设我们需要对日志进行处理。我们先声明一个接口ILogger:

 

  public interface ILogger
{
void Write(string log);

}

我们可以有多种方法实现这个接口,我们假设希望写日志到文件中:

复制代码
  public class FileLogger:ILogger
{

#region ILogger Members

public void Write(string log)
{
Console.WriteLine("Write log in file.");
}

#endregion
}
复制代码

我们在实际生活中对数据库的选择也是多种多样的。我们创建一个数据库的基类:

public class Database
{
}

创建一个派生类:

复制代码
public class CustomerDatabase : Database
{
private ILogger _logger;
public CustomerDatabase(ILogger logger)
{
_logger = logger;
}
}
复制代码

注意它的构造器的参数是ILogger类型。首先我们要创建一个Unity 容器:

UnityContainer container = new UnityContainer();

接下来我们需要在容器中注册一种类型,它是一个类型的映射,接口类型是ILogger,我希望返回的类型是FileLogger:

container.RegisterType<ILogger, FileLogger>();

然后我们使用Resolve 方法:

Database database = container.Resolve<CustomerDatabase>();

经过调试我们可以发现,如果在容器中没有注册的类型。执行Resolv方法后,Unity尝试创建该类型,会执行该类的构造器。最后database变量的类型就是CustomerDatabase,而且它的私有字段ILogger的当前实例也为FileLogger。

示例2:类型映射

我们希望返回一个日志类的实例,无论它是哪个实现类。我们可以直接在Resolve的类型中指定类型为接口ILogger:

UnityContainer container = new UnityContainer();
container.RegisterType<ILogger, FileLogger>();
ILogger logger = container.Resolve<ILogger>();

每一次 container都会给我们返回一个新的logger实例。

示例3:单例模式的注册

如果我们想告诉Unity,我们想控制生命周期,我们想用单例模式。RegisterType方法包含一个重载,将使用LifetimeManager。每次我们在想获得到database实例时,unity总是会返回第一次我创建的CustomerDatabase。

UnityContainer container = new UnityContainer();
container.RegisterType<Database, CustomerDatabase>
(new ContainerControlledLifetimeManager());

示例4:注册时附带key

在我们向容器里注册时,可以附带一个string 类型的Key值。

UnityContainer container = new UnityContainer();
container.RegisterType<Database, SQLDatabase>("SQL");
container.RegisterType<Database, ORACLEDatabase>("ORACLE");
IEnumerable<Database> databases = container.ResolveAll<Database>();
Database database = container.Resolve<Database>("SQL");

我们分别向容器中注册了名为“SQL“和”ORACLE“的Database。当我们使用ResolverAll方法是。容器会返回容器中所有类型为Database的类。

这时我们如果仅仅想回去SQL的实例,我们可以使用container.Resolve<Database>("SQL");

示例5:注册已经存在的实例

通过下边方式我们可以在container中注册一个实例:

  UnityContainer container = new UnityContainer();
container.RegisterInstance<Database>(new SQLDatabase());
container.RegisterInstance<Database>("Oracle", new ORACLEDatabase());
Database database = container.Resolve<Database>();
Database oracleDatabase = container.Resolve<Database>("Oracle");

看起来和上边的方式没什么不同。重要的是,当我们使用RegisterInstance方法时,Unity会注册一个单例。

我们还有一种方法可以把已经存在的实例注入到容器中。

             UnityContainer container = new UnityContainer();
container.RegisterType<ILogger, FileLogger>();
SQLDatabase existDatabase = new SQLDatabase();
container.BuildUp(existDatabase);
container.RegisterInstance<Database>(existDatabase);
Database database = container.Resolve<Database>();

就如上边代码中,我们已经存在一个database 是DB2Database。你希望Unity做的是把依赖注入到容器中。

我们用BuildUp方法告诉Unity我们的想法。这时候Unity回去DB2Database 类,如果他发现了[Dependency]这个特性。他就自动的把我们前边注册的FileLogger注入到DB2Database的Logger字段中。

以下是DB2Database类:

public class DB2Database:Database
{
[Dependency]
public ILogger Logger { get; set; }
}

使用配置文件来实现关系映射

我们也可以再web.config里配置 文件的依赖关系映射。首先我打开web.config文件。按照如下结构添加section。这里我只是简单的映射了ILogger 接口和FileLogger。并且指定了生命周期是单例。

复制代码
<configuration>
<configSections>
<section name="unity"
type
="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,
Microsoft.Practices.Unity.Configuration"
/>
</configSections>
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
<container name="containerOne">
<types>
<type type="UnityDemo_ConsoleApplication.ILogger" mapTo="UnityDemo_ConsoleApplication.FileLogger"
lifeTime
="Singleton"/>
</types>

</container>

</unity>
...
...
</configuration>
复制代码

如果你想更详细的了解元素和属性的使用,可以看以下Unity xml中配置的结构图:



更详细了解,请参见:

http://msdn.microsoft.com/en-us/library/ff647848.aspx

http://msdn.microsoft.com/zh-cn/library/dd203230.aspx

如何读取配置 并加载

Unity同样支持我们在配置文件里写设定映射关系。

首先我们要引入命名空间: Microsoft.Practices.Unity.Configuration;

在Unity2.0以上版本,已经废弃了以前的方法。现在我们有2种方式可以读取配置。

第一种,我们使用configurationManager:

引用命名空间:System.Configuration

            IUnityContainer myContainer = new UnityContainer();

myContainer.LoadConfiguration("containerOne ");
UnityConfigurationSection section
= (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
section.Configure(myContainer, "containerOne");

第二种,我们可以直接用容器读取配置信息:

IUnityContainer myContainer = new UnityContainer();
myContainer.LoadConfiguration("containerName");

通过 Injection API 指定依赖

假设我们有一个类GenericDatabase:
 

复制代码
public class GenericDatabase:Database
{
private string _connectionString;
public ILogger Logger { get; set; }

public GenericDatabase(string connectionString)
{
_connectionString = connectionString;
}
}
复制代码

在这里我们要通过Injection API 来为这个类注入connectionString 和 Logger。

首先我们还和前边的一样注册映射关系:

            IUnityContainer container = new UnityContainer();
container.RegisterType<ILogger, FileLogger>();
container.RegisterType<Database, GenericDatabase>();

然后通过Injection API 为GenericDatabase注入ConnectionStrings和Logger:

复制代码
container.Configure<InjectedMembers>()
.ConfigureInjectionFor<GenericDatabase>(
new InjectionConstructor(
ConfigurationManager.ConnectionStrings["ConnectionStrings"] == null
? "defaultConnectionString" : ConfigurationManager.ConnectionStrings["ConnectionStrings"].ConnectionString),
new InjectionProperty("Logger")
);
Database database = container.Resolve<Database>();
复制代码

这样我们最后获得的database 就包含了connection 和 Logger。

嵌套式容器

容器是可以嵌套的,获取实例时遵循的规则是,如果���容器里不包含需要的对象,则会去父容器获取。如果有,则从自己里获取。

一旦父容器销毁,子容器也随之销毁。

复制代码
UnityContainer parentContainer = new UnityContainer();
IUnityContainer childContainer1 = parentContainer.CreateChildContainer();
IUnityContainer childContainer2 = parentContainer.CreateChildContainer();
parentContainer.RegisterType<ILogger, FileLogger>(new ContainerControlledLifetimeManager());
childContainer1.RegisterType<ILogger, EventLogger>(new ContainerControlledLifetimeManager());
//应该从parentContainer得到FileLogger
ILogger logger = childContainer2.Resolve<ILogger>();
logger.Write("Test");
//应该从自己本身得到eventLogger

ILogger logger2 = childContainer1.Resolve<ILogger>();
复制代码


在MVC 中使用Unity注入Controller

在MVC2中我们会写一个controlleFactory 继承自DefaultControllerFactory。

并且override GetControllerInstance()这个方法。

MVC3对于依赖注入提供更好的支持。我们可以使用- IDependencyResolver 和 IControllerActivator 来实现对controller的注入。

具体实现如下:

创建一个MVC3项目。

我们要实现MVC3中新提供 的两个接口:IDependencyResolver和IControllerActivator

IDependencyResolver公开两个方法 - GetService的GetServices.The GetService方法解决了单独注册的服务,支持任意对象的创建,GetServices解决注册多个服务。IDependencyResolver接口的实现应该委托给底层的依赖注入容器提供注册服务请求的类型。当有没有注册的服务请求的类型,ASP.NET MVC框架预计这个接口的实现返回GetService为空,并从GetServices返回空集合。让我们以统一提供依赖注入工作IDependencyResolver intreface派生创建一个自定义的依赖解析器类。

我们定义一个类名为UnityDependencyResolver:

复制代码
  public class UnityDependencyResolver : IDependencyResolver
{
IUnityContainer container;
public UnityDependencyResolver(IUnityContainer container)
{
this.container = container;
}

public object GetService(Type serviceType)
{
try
{
return container.Resolve(serviceType);
}
catch
{
return null;
}
}

public IEnumerable<object> GetServices(Type serviceType)
{
try
{
return container.ResolveAll(serviceType);
}
catch
{
return new List<object>();
}
}
}
复制代码

实现两个方法GetService和GetServices。使用Unity容器返回我们需要的Service或者ojbect。

实现两个方法GetService和GetServices。使用Unity容器返回我们需要的Service或者ojbect。

ASP.NET MVC 3已经推出了一个新的接口IControllerActivator,让您激活与自定义的行为控制器,并且可以使用依赖注入.让我们创建一个派生自IControllerActivator 接口的一个自定义的控制器

IController IControllerActivator.Create( System.Web.Routing.RequestContext requestContext,
Type controllerType)
{
return DependencyResolver.Current
.GetService(controllerType) as IController;
}

DependencyResolver.Current.GetService会执行我们自己定义的UnityDependencyResolver中的方法。

定义好这两个类,我们找到Global.asax.cs,并在其中中添加一个私有方法GetUnityContainer():

复制代码
        private IUnityContainer GetUnityContainer()
{
//Create UnityContainer
IUnityContainer container = new UnityContainer()
.RegisterType<IControllerActivator, CustomControllerActivator>()
.RegisterType<ILogger, FlatFileLogger>();
return container;
}
复制代码

这个方法定义了一个新的容器。并且注册了映射关系。我们要返回的container中包含:CustomControllerActivator和FlatFileLogger。

IUnityContainer container = GetUnityContainer();

DependencyResolver.SetResolver(new UnityDependencyResolver(container));

上边的都做好了。我们在Application_Start方法中添加如下代码:

protected void Application_Start()
{
...
IUnityContainer container = GetUnityContainer();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}

首先我们通过GetUnityContainer方法获得container,并且设置当前的Resolver是我们自己实现的UnityDependencyResolver。

在Controller中我们只需要添加一个[Dependency]特性,就可以很方便的获取到我们注入的Logger。

复制代码
  public class HomeController : Controller
{
[Dependency]
public ILogger Logger { get; set; }

public ActionResult Index()
{

ViewBag.Message = "Welcome to ASP.NET MVC!";

Logger.GetType();

return View();
}

public ActionResult About()
{
return View();
}
}
复制代码

我们可以使用Logger.GetType()查看到,我们当前的Logger就是我们之前注册的FlatFileLogger。

 

参考资料

http://unity.codeplex.com/      

http://www.cnblogs.com/Terrylee/archive/2008/02/21/unity-application-block-part1.html         

http://msdn.microsoft.com/zh-cn/library/ff663144.aspx    

http://www.martinfowler.com/articles/injection.html        

http://weblogs.asp.net/shijuvarghese/archive/2011/01/21/dependency-injection-in-asp-net-mvc-3-using-dependencyresolver-and-controlleractivator.aspx     

http://www.pnpguidance.net/Screencast/UnityDependencyInjectionIoCScreencast.aspx               

http://weblogs.asp.net/shijuvarghese/archive/2011/01/21/dependency-injection-in-asp-net-mvc-3-using-dependencyresolver-and-controlleractivator.aspx                 

http://msdn.microsoft.com/en-us/library/ff660878(v=pandp.20).aspx          

http://msdn.microsoft.com/zh-cn/library/dd203182.aspx

asp.net mvc多文件上传

本文主要介绍asp.net mvc中使用controllerContext.HttpContext.Request.Files上传多个文件。
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace MvcApplication2.Controllers
{
     public class HomeController : Controller
     {
         public ActionResult Index()
         {
             return View();
         }
  
         public ActionResult FileUploads()
         {
             string pathForSaving = Server.MapPath("~/Uploads");
             if (this.CreateFolderIfNeeded(pathForSaving))
             {
                 foreach (string file in Request.Files)
                 {
                     HttpPostedFileBase uploadFile = Request.Files[file] as HttpPostedFileBase;
                     if (uploadFile != null && uploadFile.ContentLength > 0)
                     {
                        var path = Path.Combine(pathForSaving, uploadFile.FileName);
                         uploadFile.SaveAs(path);
                     }
                  }
              }
              return RedirectToAction("Index");
          }
 
          // 检查是否要创建上传文件夹
          private bool CreateFolderIfNeeded(string path)
          {
              bool result = true;
              if (!Directory.Exists(path))
              {
                 try
                 {
                     Directory.CreateDirectory(path);
                 }
                 catch (Exception)
                 {
                     //TODO:处理异常
                     result = false;
                 }
           }
           return result;
       }
    }
} 
Home/Index.cshtml视图
@{
      ViewBag.Title = "Index";
      Layout = "~/Views/Shared/_Layout.cshtml";
 }
  
  @using (Html.BeginForm("FileUploads", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
  {
      


}

asp.net mvc如何使用Elmah处理错误日志?(转)

常在服务器端处理用户请求时.特别是针对Web应用程序.当出现异常是可以根据日志操作记录还原异常出现时操作步骤.而记录异常堆栈信息判断问题出现问题位置. 为了跟踪和记录服务器行为.特别是针对出现异常时构建简单、统一的异常处理模式就显得尤为重要.

如果有一个基础的架构用来记录服务器端中日志和事件.那么对于调试和 在问题的解决就变得更加简单直接.针对日志记录.可能针对大部分开发人员.首先表现明显就是应用程序底层或是运行时中存在Bug或是特定情况下Crash 掉等. 比较明显的行为.这时日志记录目的是为了跟踪应用程序的底层行为.了解出现异常时应用程序内部所执行的过程. 能够帮助开发人员和软件测试找到应用程序崩溃的原因. 快速解决问题.

而还有一些情况.是很难再开发阶段把问题暴露出来.类似性能问题.而此时如果有了日志记录服务端行为.则可以通过提供的详细执行时间记录可以很方便的找出应用的性能瓶颈.定位这些比较”隐性“问题.

所以花了点时间研究日志记录组件.说说个人看法.

在开源日志管理上当然不得不提到是LogStash .

2013-01-22_162111

它是一个应用程序日志、事件的传输、处理、管理和搜索的平台.基于 HTML5、Jquery、Css3和SVG等技术.所以也是跨平台的、跨浏览器的.可应用任何的Asp.net开发.可以用它来统一对应用程序日志进行 收集管理.最难得可贵的提供Web接口用户查询和统计. 所以特点是跨平台同时也是足够开放的.[这就是开源社区的力量.]推荐.

另外一个就是从Java移植过来的.Net版本Log4Net

 

 

ls-logo

这个可能给位已经很熟悉了.Log4net是从java平台下非常优 秀的日志记录框架Log4J移植到.NEt下版本.它也是Apache基金资助的项目的一部分.Log4net可以帮助我们把日志信息输出到各种不同目标 (文本文件、数据库、控制台等)的.net类库,它可以容易的加载到开发项目中,实现程序调试和运行的时候的日志信息输出,提供了比.net自己提供的 debug类和trace类的功能更多,使用起来也是非常的简单.

在说道本篇即将提到的Elmah.

2013-01-22_163710

 

 

Elmah其实是[The Error Logging Modules and Handlers]缩写.它是专用于ASP.NET的完全可热插拔的 错误日志记录工具。其特点就是无需ASP.NET程序重新编译,即可通过配置web.config(或machine.config)来实现整个应用程序 甚至是IIS中所有ASP.NET应用程序的错误日志记录工作。它支持日志的多种存储方式(各种数据库、XML、内存存储),除了提供一个界面用于查询日 志详细信息外,还可以通过E-MAIL、RSS订阅或Twitter发布方式通知错误信息给相关人员.

分别试用一下.

LogStash最大的特点是除了跨平台本身之外.它最强大的地方是 其提供丰富的插件的.各种灵活自定义规则.输出各种各样的日志结果.可以在不同的服务器上对不同的数据来源做自定义的filter,然后输出到不同的目的 插件上去.这样对于分布式是采集日志提供很好解决方案.类似要监控A B服务器上日志.可以再C服务器上接受日志记录数据并分析让后分发给D服务器做报警和容错处理. 自由开放.可以任意端采集日志数据.

Log4Net包含了主要有四种重要的组件,分别是Logge, Repository, Appender以及 Layout.功能强大.可以自定义日志输出级别.但我认为对于规模偏小的应用程序.在配置方式和灵活度显得不够Clean.

本篇来尝试Elmah在Asp.net MVC 4使用.

首先Build 空的Asp.net MVC 4 Project:

2013-01-22_172012

添加Elmah引用:

2013-01-22_172204

如果采用VS2012则如上关于Elmah组建已经配置成功.其实这个过程做了两件事:

A:将Elmah.dll复制到程序的根目录的Bin文件夹下.并当前项目的引用.

B:向项目根目录下Web.Config文件添加如下内容

在webConfig文件中添加如下内容:

 1:   <configSections>
 2:     <sectionGroup name="elmah">
 3:       <section name="security" requirePermission="false" type="Elmah.SecuritySectionHandler, Elmah" />
 4:       <section name="errorLog" requirePermission="false" type="Elmah.ErrorLogSectionHandler, Elmah" />
 5:       <section name="errorMail" requirePermission="false" type="Elmah.ErrorMailSectionHandler, Elmah" />
 6:       <section name="errorFilter" requirePermission="false" type="Elmah.ErrorFilterSectionHandler, Elmah" />
 7:     </sectionGroup>
 8:   </configSections>
 9:  
 10:   <httpHandlers>
 11:       <add verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" />
 12:   </httpHandlers>
 13:    
 14:   <httpModules>
 15:       <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" />
 16:   </httpModules>
 

关于Elmah项目引用配置基本完成.如果你不习惯NuGEt也可以采用如上手工的方式添加项目引用.

此时在homeController中throw 一个nullException :

 1:   public class HomeController : Controller
 2:     {
 3:         public ActionResult Index()
 4:         {
 5:             //throw new null exception for test
 6:             throw new ArgumentNullException();
 7:             return View();
 8:         }
 9:     }

运行效果如下:

2013-01-22_173931

很明显.当我们throw一个异常后.,会出现报错的黄页.在来看看Elmah是否记录本次执行过程中出现ArgumentNullException.

2013-01-22_174214

可以看到Elmah已经如期的扑捉到当前应用程序的异常.ELMAH在后台记录了错误信息,并为我们提供了查询错误日志信息的界面,只需要简单的操作,就完成了基本的需求.

其实Elmah处理原理.当我们请求页面报错时.在返回黄页错误时首 先被httpModules中名为ErrorLog模块进行拦截. 该模块将本次请求出错的信息保存起来.-默认是放置在内存中.便于即时调试.但用户输入elmah.axd要查看日志信息时. 首先httpHandlers捕获到该请求.并交给专门处理elmah.axd的处理程序.该模块把错误日志View返回给用户.可见Elmah核心技术 还是基于HttpModules和HttpHandlers来实现的.

在添加完对Elmah引用可见在web.config同时添加Elmah节点 如下:

 1:  <elmah>
 2:     <!--
 3:  See http://code.google.com/p/elmah/wiki/SecuringErrorLogPages for 
 4:  more information on remote access and securing ELMAH.
 5:  -->
 6:     <security allowRemoteAccess="false" />
 7:   </elmah>

Elmah通过该节点对外公开功能配置项.该配置选项功能丰富.开篇提到Elmah对存储方式支持包含:

 

首先如果你只是引用Elmah而没有配置采用什么存储形式.Elmah默认设置为内存存储的方式.虽然这种方式便于开发调试.但在部署生产环境后还是推荐对数据要进行持久化存储. Xml文件或是采用支持的数据库.

改成文件存储方式只需要在配置项添加如下代码即可:

 1:   <elmah>
 2:     <!--
 3:         See http://code.google.com/p/elmah/wiki/SecuringErrorLogPages for 
 4:         more information on remote access and securing ELMAH.
 5:     -->
 6:     <security allowRemoteAccess="false" />
 7:     <errorLog type="Elmah.XmlFileErrorLog, Elmah" logPath="~/Static/Log/" />
 8:   </elmah>

该配置必需确认LogPath路径目录是完整存在的.测试会发现在本地文件中会出现一个XML文件:

2013-01-26_152341

这种方式虽然简单直观.但Elmah设计方式在每次运行如果应用程序出错一旦扑捉到.就独立生成一个独立的文件.这种方式会导致服务器端存在大量冗余文件.且对这些文件管理也是一个问题.

在数据可视化和管理上数据库依然是最理想的选择.这里采用SQlServer2008 版本测试.在构建Elmah支持SQLServer数据支持需要如下三个操作:

A: 需要告诉Elmah 需要连接什么类型的数据库

B: Elmah如何连接这些数据库.也就是连接字符串需要提供

C: 在指定数据库中已经存在对应存储Log日志表和视图存储过程.

实际操作首先需要Elmah节点添加如下内容:

 1:   <errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="SQlServerConStr" />

在该数据执行如下SQL语句.请参考官方的连接.

Elmah SQL Server Script File:http://code.google.com/p/elmah/source/browse/src/Elmah/SQLServer.sql

执行sQL语句完成后会在当前数据库看到表:

2013-01-26_150301

当再次运行应用程序.在Throw ArgumentNullException时查询数据库:

2013-01-26_151242

可见简单实用.另外针对SQL语句执行全部以官方标准为主.不同数据库之间SQL Script脚本会存在一定的差异.

在使用Elmah过程发一下一些特点.这里需要说明一下.

Elmah是通过Http Modules 和Http Handler来记录和展示程序捕获的异常. 但是如果你在应用程序中添加异常处理模块.Try-Catch Elmah是无法记录到的.或是在Catch后在Throw出来. 在整个应用程序异常链上. 只有最终的异常抛给了Asp.net运行时Elmah组件才能捕获到并记录.

有很多人认为加入Elmah组件后能够处理应用异常.其实本质上Elmah本质上是一个日志记录工具.并没有处理异常的能力.所以如果异常发生.不会改变原来应用程序给用户体验.依然还会出现黄色页面.

在官方Note明确提到一个例外.:

ELMAH捕获异常是基于HttpApplication对象的Error事件。

如果软件项目中的一些处理导致了HttpApplication事件无法被触发(比如在发生异常后,还没来得及执行Application_Error,就执行了Server.ClearError()方法,

会阻止Error事件的触发,再比如,如果一个异常被try-catch捕获到,并且没有再次throw,那么异常也是不会最终触发Error事件)

日志记录工具还是不少的,比如著名的Log4net以及Enterprise Library中的Logging Application Block。 可以说,这些工具相对ELMAH来说,太重量级了,他们可以记录各种日志信息,比如监视代码中变量的变化情况,周期性的记录到文件中供其他应用进行统计分 析工作;跟踪代码运行时轨迹,作为日后审计的依据;担当集成开发环境中的调试器的作用,向文件或控制台打印代码的调试信息。因此,如果仅仅是记录 ASP.NET的错误日志.而Elmah开源且足够Clean.首选.

asp.net mvc中的area是什么?

ASP.NET MVC中,是依靠某些文件夹以及类的固定命名规则去组织model实体层,views视图层和控制层的。如果是大规模的应用程序,经常会由不同功能的模块组成,而每个功能模块都由MVC中的三层所构成,因此,随着应用程序规模的增大,如何组织这些不同功能模块中的MVC三层的目录结构,有时对开发者来说显得是种负担。

  幸运的是,ASP.NET MVC允许开发者将应用划分为“区域”(Area)的概念,每个区域都是按照asp.net mvc的规定对文件目录结构和类的命名规则进行命名。在本文中,将介绍如何在ASP.NET MVC应用中使用Area进行模块管理。

  什么是Areas?

  简单来说,Areas是将ASP.NET MVC应用按照不同的功能模块划分,对每个功能模块使用ASP.NET MVC规则的目录结构和命名方法。考虑如下图的场景:

 

 

ASP.NET MVC中Area分层模块处理大解密

 


  在上图中可以看到,这个应用程序由三个功能模块组成,分别为Blog,Help Desk和Shopping。如果不使用区域Areas的话,则必须将所有的控制层和视图层文件都放在各自的目录中去,显然,不能在不同的功能模块中的对控制器有相同的命名,比如不能在Blog模块中命名HomeController,同时也对HelpDesk模块命名HomeController。可以解决的方法是,在一个控制器中将所有的模块中的action方法都放在一起,或者创建两个控制器,以不同的方法命名(BlogHomeController和HelpDeskHomeController).

 

  如果使用了areas进行模块划分,则每个功能模块都会复制MVC的目录结构。比如,每个模块都会有自己的控制层,视图层和实体层的目录。因此,可以在Blog模块中拥有HomeController类,在HelpDesk模块中也可以同名的HomeController类。所以,实际上在上面的例子中,将会有4个MVC的结构,一个是主程序的,三个分别是三个模块(Blog, HelpDesk and Shopping的)

  增加新的Area

  下面我们来开始学习如何新增Area。首先使用vs.net 2010新建一个MVC应用。然后在方案解决器中,鼠标右键点击后在出现的菜单中选择新增>Area,就会显示如下图的对话框:

 

 

ASP.NET MVC中Area分层模块处理大解密

 


  在其中输入要增加的Area的名称,比如HelpDesk。在输入三个不同的Area后,项目呈现如下图的结构:

 

 

 

ASP.NET MVC中Area分层模块处理大解密

 


  可以看清晰看到,整个应用是有一个叫Areas的目录,其中下面三个模块都有各自的控制层,模型层和视图层的目录了。同样,在应用的外层目录中,依然有实体层和控制层和视图层的目录。

 

  在MVC框架中注册Area

  除了建立好目录结构外,还需要告诉ASP.NET MVC框架area已经建立好了,这个属于注册的步骤,幸运地在建立一个新的area时已经自动建立起来了。请注意在每一个area的目录下,都会自动产生一个注册的类文件(比如BlogAreaRegistration.cs, HelpDeskAreaRegistration.cs,)。每一个area的注册类���件都是继承自AreaRegistration这个基类,比如HelpDeskAreaRegistration的类文件代码如下:

  

 

  public class HelpDeskAreaRegistration : AreaRegistration

  public override string AreaName

  get

  return HelpDesk;

  public override void RegisterArea(AreaRegistrationContext context)

  context.MapRoute(

  HelpDesk_default,

  HelpDesk/{controller}/{action}/{id},

  new { action = Index, }

  );


  可以看到,HelpDeskAreaRegistration类覆写了AreaName属性和RegisterArea方法。RegisterArea方法则在MVC中注册了新的路由信息。

 

  在每一个area中都必须有一个象这样的注册类。但什么时候去使用这些注册的类呢?如果打开Global.asx这个文件,会发现在Application_Start事件中会发现如下代码:

  

 

  protected void Application_Start()

  AreaRegistration.RegisterAllAreas();

  RegisterGlobalFilters(GlobalFilters.Filters);

  RegisterRoutes(RouteTable.Routes);


  这里读者可以看到,调用了AreaRegistration类的静态方法RegisterAllAreas()去注册所有的are注册文件,而RegisterAllAreas()方法会去逐一调用应用中所有area的RegisterArea()方法。

 

  接下来,在主程序及每个area中都增加HomeController,这样,就会有四个以HomeController命名的控制类,如下所示:

  

 

  public class HomeController : Controller

  public ActionResult Index()

  return View();


  同样,鼠标右击每个Index()方法,在弹出的菜单中新增加一个Index视图,这样总共有4个index视图页面。运行应用,可以看到如下图的效果,下图是其中运行HelpDesk Area时的效果,请留意其中的URL

 

 

 

ASP.NET MVC中Area分层模块处理大解密

 


  Areas之间的调用

 

  ASP.NET MVC中,经常需要在控制层的不同方法之间进行互相调用。如果没特别指定,则默认为同一个area中的action方法和控制器之间的调用。如果需要在不同的area之间进行互相调用,可以使用如下方法:

  

 

  %= Html.ActionLink(Main Area, Index, Home, new { area = }, null)%>

  br />br />

  %= Html.ActionLink(Blog Area, Index, Home, new { area = Blog }, null)%>

  br />br />

  %= Html.ActionLink(Help Desk Area, Index, Home, new { area = HelpDesk }, null)%>

  br />br />

  %= Html.ActionLink(Shopping Area, Index, Home, new { area = Shopping }, null)%


  可以看到,上面使用了ActionLink()方法产生链接,注意其中的第4个参数,使用new {area=“Blog”}这样形式的参数,指出调用的是哪一个area中action方法。

 

  使用RedirectToAction

  同样,我们经常要在某个area中的action方法去调用另外一个area方法中的action,这个时候要如何做呢?代码如下:

  

 

  public ActionResult Index()

  return RedirectToAction(Index, Home, new { Area = HelpDesk });


  这里,使用了RedirectToAction方法去调用另外一个area中的action方法,同样是使用了new {Area=“HelpDesk”}的方式,指定area的名称即可,所以这里调用了HelpDesk Area中的index()方法。

 

  小结

  在本文中,介绍了ASP.NET MVC中的Area的概念,Area模块化的方式,能将复杂的应用划分为各个模块,并在每个模块中都能按照MVC的架构划分视图,实体和控制层的目录架构,这样更有利于项目的架构组织,更清晰容易在各模块之间进行对应的调用。