Heim > Artikel > Backend-Entwicklung > Lösung für die EntLib-Ausnahmebehandlung unter ASP.NET
ASP.NET MVC ist ein sehr erweiterbares Entwicklungsframework. In diesem Artikel werde ich die Integration mit EntLib durch seine Erweiterung implementieren und eine vollständige Lösung für die Ausnahmebehandlung bereitstellen.
Der Ausnahmebehandlungs-Anwendungsblock von EntLib ist ein gutes Ausnahmebehandlungs-Framework, das es uns ermöglicht, Ausnahmebehandlungsstrategien durch Konfiguration zu definieren. ASP.NET MVC ist ein sehr erweiterbares Entwicklungsframework. In diesem Artikel werde ich es über seine Erweiterung in EntLib integrieren und eine vollständige Ausnahmebehandlungslösung bereitstellen.
1. Grundlegende Ausnahmebehandlungsstrategie
Besprechen wir zunächst die spezifische Ausnahmebehandlungsstrategie unserer Lösung:
Bei Ausnahmen, die durch die Ausführung einer Action-Methode des Controllers ausgelöst werden, behandeln wir diese gemäß der angegebenen Konfigurationsstrategie. Wir können gängige Ausnahmebehandlungsmethoden wie Protokollierung, Ausnahmeersetzung und Kapselung übernehmen.
Wenn die Ausnahmebehandlungsrichtlinie vorschreibt, dass sie ausgelöst werden müssen, werden sie automatisch zur Fehlerseite weitergeleitet passender Ausnahmetyp. Wir pflegen eine übereinstimmende Beziehung zwischen dem Ausnahmetyp und der Fehleransicht.
Wenn die Ausnahmebehandlungsrichtlinie vorschreibt, dass sie nicht ausgelöst werden muss, entspricht dies einer Operation, die mit der aktuellen Aktion übereinstimmt wird ausgeführt. FehlerbehandlungZu behandelnde Aktion. Die Aktionsmethode zur Ausnahmebehandlung verwendet standardmäßig die Benennungsregel „On{Action}Error“, und der aktuelle Kontext wird an die Parameter der Aktionsmethode zur Ausnahmebehandlung gebunden. Darüber hinaus setzen wir die Fehlermeldung des aktuellen ModellsStatus;
Wenn der Benutzer die entsprechende Ausnahmebehandlungsaktion nicht definiert hat, wird die „ Für die Ausnahmebehandlung wird weiterhin die Methode „Seitenumleitung“ verwendet.
2. Ausnahmebehandlung durch benutzerdefinierte Aktionen
Um den Lesern ein tiefes Verständnis der oben vorgestellten Ausnahmebehandlungsseite zu vermitteln, führen wir eine durch Praktische Demonstration. Diese Instanz wird verwendet, um die Benutzeranmeldung zu simulieren. Wir definieren das folgende Modell, das nur zwei -Attribute enthält: Benutzername und Passwort: LoginInfoModel.
namespace Artech.Mvc.ExceptionHandling.Models { public class LoginInfo { [Display(Name ="User Name")] [Required(ErrorMessage = "User Name is manadatory!")] public string UserName { get; set; } [Display(Name = "Password")] [DataType(DataType.Password)] [Required(ErrorMessage = "Password is manadatory!")] public string Password { get; set; } } }
Wir definieren den folgenden AccountController, der eine Unterklasse unseres benutzerdefinierten BaseControllers ist. AccountController ruft während der Erstellung den Konstruktor der Basisklasse auf. Die durch angegebenen Parameter stellen den Konfigurationsnamen der Ausnahmebehandlungsstrategie dar. Die SignIn-Methode stellt den Vorgang „Anmelden“ dar, und OnSignInError stellt den dem Vorgang entsprechenden Ausnahmebehandlungsvorgang dar. Wenn die im SignIn-Vorgang ausgelöste Ausnahme behandelt wird und nicht mehr ausgelöst werden muss, wird OnSignInError aufgerufen und der ModelState wurde mit der entsprechenden Fehlermeldung festgelegt.
public class AccountController BaseController { public AccountController() base("myPolicy") { } public ActionResult SignIn() { return View(new LoginInfo()); } [HttpPost] public ActionResult SignIn(LoginInfo loginInfo) { if (!ModelState.IsValid) { return this.View(new LoginInfo { UserName = loginInfo.UserName }); } if (loginInfo.UserName != "Foo") { throw new InvalidUserNameException(); } if (loginInfo.Password != "password") { throw new UserNamePasswordNotMatchException(); } ViewBag.Message = "Authentication Succeeds!"; return this.View(new LoginInfo { UserName = loginInfo.UserName }); } public ActionResult OnSignInError(string userName) { return this.View(new LoginInfo { UserName = userName }); } }
Die in der SignIn-Operationsmethode speziell definierte Authentifizierungslogik lautet wie folgt: Wenn der Benutzername nicht „Foo“ ist, wird eine InvalidUserNameException-Ausnahme ausgelöst. Wenn das Passwort nicht „password“ ist, wird eine UserNamePasswordNotMatchException ausgelöst Ausnahme wird ausgelöst. Im Folgenden finden Sie die Definition der Ansicht, die dem Anmeldevorgang entspricht:
@model Artech.Mvc.ExceptionHandling.Models.LoginInfo @{ ViewBag.Title = "SignIn"; } @Html.ValidationSummary() @if (ViewBag.Messages != null) { @ViewBag.Messages } @using (Html.BeginForm()) { @Html.EditorForModel() <input type="submit" value="SignIn" /> }
Die bei der Initialisierung des AccountControllers angegebene Ausnahmebehandlungsrichtlinie „myPolicy“ ist in der folgenden Konfiguration definiert. Wir behandeln speziell die von der SignIn-Operationsmethode ausgelösten InvalidUserNameException und UserNamePasswordNotMatchException, und der ErrorMessageSettingHandler ist unser benutzerdefinierter Ausnahmehandler, der nur zum Festlegen der Fehlermeldung verwendet wird. Wie im folgenden Codeausschnitt gezeigt, werden beim Auslösen der beiden oben genannten Ausnahmetypen die endgültigen Fehlermeldungen als „Benutzername existiert nicht!“ und „Benutzername stimmt nicht mit Passwort überein!“ angegeben.
<exceptionHandling> <exceptionPolicies> <add name="myPolicy"> <exceptionTypes> <add name="InvalidUserNameException" type="Artech.Mvc.ExceptionHandling.Models.InvalidUserNameException, Artech.Mvc.ExceptionHandling" postHandlingAction="None"> <exceptionHandlers> <add name="ErrorMessageSettingHandler" type="Artech.Mvc.ExceptionHandling.ErrorMessageSettingHandler, Artech.Mvc.ExceptionHandling" errorMessage="User name does not exist!"/> </exceptionHandlers> </add> <add name="UserNamePasswordNotMatchException" type="Artech.Mvc.ExceptionHandling.Models.UserNamePasswordNotMatchException, Artech.Mvc.ExceptionHandling" postHandlingAction="None"> <exceptionHandlers> <add name="ErrorMessageSettingHandler" type="Artech.Mvc.ExceptionHandling.ErrorMessageSettingHandler, Artech.Mvc.ExceptionHandling" errorMessage="User name does not match password!"/> </exceptionHandlers> </add> </exceptionTypes> </add> </exceptionPolicies> </exceptionHandling>
Jetzt legen wir AccountController und Sign über das Route-Mapping als Standard-Controller und -Aktion fest und starten unsere Anwendung. Wenn Sie einen falschen Benutzernamen und ein falsches Passwort eingeben, erhalten Sie automatisch die entsprechende Fehlermeldung in der ValidationSummary.
3. Behandlung von Ausnahmen über die konfigurierte Fehleransicht
In der obigen Konfiguration für die beiden Ausnahmen InvalidUserNameException und UserNamePasswordNotMatchException Die Konfiguration Die Strategie des Typs setzt das PostHandlingAction-Attribut auf „None“, was bedeutet, dass die ursprüngliche Ausnahme und die behandelte Ausnahme nicht erneut ausgelöst werden. Jetzt setzen wir diese Eigenschaft auf „ThrowNewException“, was bedeutet, dass wir die behandelte Ausnahme erneut auslösen.
<exceptionHandling> <exceptionPolicies> <add name="myPolicy"> <exceptionTypes> <add name="InvalidUserNameException" type="Artech.Mvc.ExceptionHandling.Models.InvalidUserNameException, Artech.Mvc.ExceptionHandling" postHandlingAction="ThrowNewException"> ... <add name="UserNamePasswordNotMatchException" type="Artech.Mvc.ExceptionHandling.Models.UserNamePasswordNotMatchException, Artech.Mvc.ExceptionHandling" postHandlingAction="ThrowNewException"> ... </add> </exceptionTypes> </add> </exceptionPolicies> </exceptionHandling>
按照我们上面的异常处理策略,在这种情况下我们将采用“错误页面”的方式来进行异常处理。也HandleErrorAttribute的处理方式类似,我们支持异常类型和Error View之间的匹配关系,而这是通过类似于如下的配置来定义的。值得一提的是,这里的异常类型是经过处理后重新抛出的异常。
<artech.exceptionHandling> <add exceptionType="Artech.Mvc.ExceptionHandling.Models.InvalidUserNameException, Artech.Mvc.ExceptionHandling" errorView="InvalideUserNameError"/> <add exceptionType="Artech.Mvc.ExceptionHandling.Models.UserNamePasswordNotMatchException, Artech.Mvc.ExceptionHandling" errorView="UserNamePasswordNotMatchError"/> </artech.exceptionHandling>
如上面的配置所示,我们为InvalidUserNameException和UserNamePasswordNotMatchException这两种异常类型定义了不同的Error View,分别是“InvalideUserNameError”和“UserNamePasswordNotMatchError”,详细定义如下所示:
@{ Layout = null; } <!DOCTYPE html> <html> <head> <title>Error</title> </head> <body> <p style="colorRed; font-weightbold">Sorry,the user name you specify does not exist!</p> </body> </html> @{ Layout = null; } <!DOCTYPE html> <html> <head> <title>Error</title> </head> <body> <p style="colorRed; font-weightbold">Sorry, The password does not match the given user name!</p> </body> </html>
现在我们按照上面的方式运行我们的程序,在分别输入错误的用户名和密码的情况下会自动显现相应的错误页面。
四、自定义ActionInvoker:ExceptionActionInvoker
对于上述的两种不同的异常处理方式最终是通过自定义的ActionInvoker来实现的,我们将其命名为ExceptionActionInvoker。如下面的代码片断所式,ExceptionActionInvoker直接继承自ControllerActionInvoker。属性ExceptionPolicy是一个基于指定的异常策略名称创建的ExceptionPolicyImpl 对象,用于针对EntLib进行的异常处理。而属性GetErrorView是一个用于获得作为错误页面的ViewResult对象的委托。整个异常处理的核心定义在InvokeAction方法中,该方法中指定的handleErrorActionName参数代表的是“异常处理操作名称”,整个方法就是按照上述的异常处理策略实现的。
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using Artech.Mvc.ExceptionHandling.Configuration; using Microsoft.Practices.EnterpriseLibrary.Common.Configuration; using Microsoft.Practices.EnterpriseLibrary.ExceptionHandling; namespace Artech.Mvc.ExceptionHandling { public class ExceptionActionInvoker ControllerActionInvoker { protected ExceptionHandlingSettings ExceptionHandlingSettings{get; private set;} protected virtual Func<string, HandleErrorInfo, ViewResult> GetErrorView { get; private set; } public ExceptionPolicyImpl ExceptionPolicy { get; private set; } public ExceptionActionInvoker(string exceptionPolicy,Func<string, HandleErrorInfo, ViewResult> getErrorView) { this.ExceptionPolicy = EnterpriseLibraryContainer.Current.GetInstance<ExceptionPolicyImpl>(exceptionPolicy); this.GetErrorView = getErrorView; this.ExceptionHandlingSettings = ExceptionHandlingSettings.GetSection(); } public override bool InvokeAction(ControllerContext controllerContext, string handleErrorActionName) { ExceptionContext exceptionContext = controllerContext as ExceptionContext; if (null == exceptionContext) { throw new ArgumentException("The controllerContext must be ExceptionContext!", "controllerContext"); } try { exceptionContext.ExceptionHandled = true; if (this.ExceptionPolicy.HandleException(exceptionContext.Exception)) { HandleRethrownException(exceptionContext); } else { if (ExceptionHandlingContext.Current.Errors.Count == 0) { ExceptionHandlingContext.Current.Errors.Add(exceptionContext.Exception.Message); } ControllerDescriptor controllerDescriptor = this.GetControllerDescriptor(exceptionContext); ActionDescriptor handleErrorAction = FindAction(exceptionContext, controllerDescriptor, handleErrorActionName); if (null != handleErrorAction) { IDictionary<string, object> parameters = GetParameterValues(controllerContext, handleErrorAction); exceptionContext.Result = this.InvokeActionMethod(exceptionContext, handleErrorAction, parameters); } else { HandleRethrownException(exceptionContext); } } return true; } catch (Exception ex) { exceptionContext.Exception = ex; HandleRethrownException(exceptionContext); return true; } } protected virtual void HandleRethrownException(ExceptionContext exceptionContext) { string errorViewName = this.GetErrorViewName(exceptionContext.Exception.GetType()); string controllerName = (string)exceptionContext.RouteData.GetRequiredString("controller"); string action = (string)exceptionContext.RouteData.GetRequiredString("action"); HandleErrorInfo handleErrorInfo = new HandleErrorInfo(exceptionContext.Exception, controllerName, action); exceptionContext.Result = this.GetErrorView(errorViewName, handleErrorInfo); } protected string GetErrorViewName(Type exceptionType) { ExceptionErrorViewElement element = ExceptionHandlingSettings.ExceptionErrorViews .Cast<ExceptionErrorViewElement>().FirstOrDefault(el=>el.ExceptionType == exceptionType); if(null != element) { return element.ErrorView; } if(null== element && null != exceptionType.BaseType!= null) { return GetErrorViewName(exceptionType.BaseType); } else { return "Error"; } } } }
五、自定义Controller:BaseController
ExceptionActionInvoker最终在我们自定义的Controller基类BaseController中被调用的。ExceptionActionInvoker对象在构造函数中被初始化,并在重写的OnException方法中被调用。
using System; using System.Web.Mvc; namespace Artech.Mvc.ExceptionHandling { public abstract class BaseController Controller { public BaseController(string exceptionPolicy) { Func<string, HandleErrorInfo, ViewResult> getErrorView = (viewName, handleErrorInfo) => this.View(viewName, handleErrorInfo); this.ExceptionActionInvoker = new ExceptionActionInvoker(exceptionPolicy,getErrorView); } public BaseController(ExceptionActionInvoker actionInvoker) { this.ExceptionActionInvoker = actionInvoker; } public virtual ExceptionActionInvoker ExceptionActionInvoker { get; private set; } protected virtual string GetHandleErrorActionName(string actionName) { return string.Format("On{0}Error", actionName); } protected override void OnException(ExceptionContext filterContext) { using (ExceptionHandlingContextScope contextScope = new ExceptionHandlingContextScope(filterContext)) { string actionName = RouteData.GetRequiredString("action"); string handleErrorActionName = this.GetHandleErrorActionName(actionName); this.ExceptionActionInvoker.InvokeAction(filterContext, handleErrorActionName); foreach (var error in ExceptionHandlingContext.Current.Errors) { ModelState.AddModelError(Guid.NewGuid().ToString() ,error.ErrorMessage); } } } } }
值得一提的是:整个OnException方法中的操作都在一个ExceptionHandlingContextScope中进行的。顾名思义, 我们通过ExceptionHandlingContextScope为ExceptionHandlingContext创建了一个范围。ExceptionHandlingContext定义如下,我们可以通过它获得当前的ExceptionContext和ModelErrorCollection,而静态属性Current返回当前的ExceptionHandlingContext对象。
public class ExceptionHandlingContext { [ThreadStatic] private static ExceptionHandlingContext current; public ExceptionContext ExceptionContext { get; private set; } public ModelErrorCollection Errors { get; private set; } public ExceptionHandlingContext(ExceptionContext exceptionContext) { this.ExceptionContext = exceptionContext; this.Errors = new ModelErrorCollection(); } public static ExceptionHandlingContext Current { get { return current; } set { current = value; } } }
在BaseController的OnException方法中,当执行了ExceptionActionInvoker的InvokeAction之后,我们会将当前ExceptionHandlingContext的ModelError转移到当前的ModelState中。这就是为什么我们会通过ValidationSummary显示错误信息的原因。对于我们的例子来说,错误消息的指定是通过如下所示的ErrorMessageSettingHandler 实现的,而它仅仅将指定的错误消息添加到当前ExceptionHandlingContext的Errors属性集合中而已。
[ConfigurationElementType(typeof(ErrorMessageSettingHandlerData))] public class ErrorMessageSettingHandler IExceptionHandler { public string ErrorMessage { get; private set; } public ErrorMessageSettingHandler(string errorMessage) { thisErrorMessage = errorMessage; } public Exception HandleException(Exception exception, Guid handlingInstanceId) { if (null == ExceptionHandlingContextCurrent) { throw new InvalidOperationException(""); } if (stringIsNullOrEmpty(thisErrorMessage)) { ExceptionHandlingContextCurrentErrorsAdd(exceptionMessage); } else { ExceptionHandlingContextCurrentErrorsAdd(thisErrorMessage); } return exception; } }
【相关推荐】
2.ASP教程
Das obige ist der detaillierte Inhalt vonLösung für die EntLib-Ausnahmebehandlung unter ASP.NET. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!