关于逻辑在MVC应用程序中的位置,我有几个问题。
这是控制器中的一个示例动作,并且想知道这是否是太多逻辑,如果是这样,你还会把它放在哪里:
FYI - Manager
是一种服务类型层,我们将BO转换为DTO / ViewModels来回另一层执行我们的BL
Public Function ChangeClaim(model As ChangeClaimViewModel) As ActionResult
Manager.SetClaimNumber(model.ClaimNumber)
Dim securityToken = Manager.ClaimSecurityToken
If (securityToken.ValidClaim) Then
Session("ClaimNumber") = model.ClaimNumber
If (Not securityToken.ConflictAccess) Then
ModelState.AddModelError("ClaimNumber", "You do not have access to this claim.")
End If
Else
ModelState.AddModelError("ClaimNumber", "Invalid claim number.")
End If
If (Not ModelState.IsValid) Then
Return View(Manager.GetViewModel())
End If
If (model.URL.Contains("ChangeClaim") OrElse model.URL.Contains("EnterClaim")) Then
model.URL = Url.Action("Index", "Home")
End If
Return Redirect(model.URL)
End Function
另外,我假设在视图中挂起bool
的ViewModel用来做逻辑就好了吗?
@if (Model.HasExposureAccess)
{
<li><a href="#tab-pane-2">@Model.Labels.Reimbursements</a></li>
}
还有其他改进建议吗?
哦,抱歉VB和&amp;混合使用C#,我工作的商店除了VB中的视图外都做了一切,我不得不争取在C#中做观点!! ??
编辑#1
至于If (securityToken.ValidClaim) Then
让我尽力让您完成整个过程,看看您是否有任何建议。
当用户尝试更改声明号时,它会进入模型,它会传递给Manager.SetClaim
方法(管理器是我们创建的一种服务层,可以使用我们现有的BO框架,不笑,是CSLA.NET V1的重大修改版本,它们是非常紧密耦合的对象,只要BL和DAL都存在于对象内部。根本不是我的选择,但你做什么:))验证它是有效的声明,用户可以访问它。我尽最大努力保持层尽可能分开:
1)MVC App
2)应用经理
3)现有的BOF
我有意义吗?
编辑#2
所以我把控制器动作的逻辑放到一个动作过滤器中,如下所示:
Public Class ValidateClaimAttribute
Inherits ActionFilterAttribute
Public Overrides Sub OnActionExecuting(filterContext As System.Web.Mvc.ActionExecutingContext)
MyBase.OnActionExecuting(filterContext)
Dim model As ChangeClaimViewModel = CType(filterContext.ActionParameters("model"), ChangeClaimViewModel)
Dim manager As IInjuredWorkerManager = DependencyResolver.Current.GetService(Of IInjuredWorkerManager)()
Dim securityToken = manager.ClaimSecurityToken
manager.SetClaimNumber(model.ClaimNumber)
If (securityToken.ValidClaim) Then
filterContext.HttpContext.Session("ClaimNumber") = model.ClaimNumber
If (Not securityToken.ConflictAccess) Then
filterContext.Controller.ViewData.ModelState.AddModelError("ClaimNumber", "You do not have access to this claim.")
End If
Else
filterContext.Controller.ViewData.ModelState.AddModelError("ClaimNumber", "Invalid claim number.")
End If
End Sub
End Class
<ValidateClaim()>
Public Function ChangeClaim(model As ChangeClaimViewModel) As ActionResult
If (Not ModelState.IsValid) Then
Return View(Manager.GetViewModel())
End If
If (model.URL.Contains("ChangeClaim") OrElse model.URL.Contains("EnterClaim")) Then
model.URL = Url.Action("Index", "Home")
End If
Return Redirect(model.URL)
End Function
这看起来更像是正确的做法吗?
编辑#3 所以,我进一步优化了这个:
<ValidateClaim()>
Public Function ChangeClaim(model As ChangeClaimViewModel) As ActionResult
If (Not ModelState.IsValid) Then
Return View(Manager.GetViewModel())
End If
Return New MyRedirect(model.URL)
End Function
Public Class ValidateClaimAttribute
Inherits ActionFilterAttribute
Public Overrides Sub OnActionExecuting(filterContext As System.Web.Mvc.ActionExecutingContext)
MyBase.OnActionExecuting(filterContext)
Dim model As ChangeClaimViewModel = CType(filterContext.ActionParameters("model"), ChangeClaimViewModel)
Dim manager As IInjuredWorkerManager = DependencyResolver.Current.GetService(Of IInjuredWorkerManager)()
Dim securityToken = manager.ClaimSecurityToken
manager.SetClaimNumber(model.ClaimNumber)
If (securityToken.ValidClaim) Then
filterContext.HttpContext.Session("ClaimNumber") = model.ClaimNumber
If (Not securityToken.ConflictAccess) Then
filterContext.Controller.ViewData.ModelState.AddModelError("ClaimNumber", "You do not have access to this claim.")
End If
Else
filterContext.Controller.ViewData.ModelState.AddModelError("ClaimNumber", "Invalid claim number.")
End If
End Sub
End Class
Public Class MyRedirect
Inherits ActionResult
Private _url As String
Public Sub New(url As String)
_url = url
End Sub
Public Overrides Sub ExecuteResult(context As System.Web.Mvc.ControllerContext)
Dim urlHelper As New UrlHelper(context.RequestContext)
If (_url.Contains("ChangeClaim") OrElse _url.Contains("EnterClaim")) Then
_url = urlHelper.Action("Index", "Home")
End If
context.HttpContext.Response.Redirect(_url)
End Sub
End Class
完整控制器代码:
Imports System.Web.Mvc
Imports System.Security.Principal
Imports Telerik.Web.Mvc
Imports System.Globalization
Namespace Controllers
<HandleException(View:="Error")>
<OutputCache(Duration:=0)>
Public MustInherit Class InjuredWorkerController
Inherits SAIF.Web.Mvc.Framework.Controllers.ContextController
Public Property Manager As IInjuredWorkerManager
Public Sub New(manager As IInjuredWorkerManager)
_Manager = manager
_Manager.ValidationDictonary = New ModelStateWrapper(ModelState)
End Sub
<ValidateClaim()>
Public Function ChangeClaim(model As ChangeClaimViewModel) As ActionResult
If (Not ModelState.IsValid) Then
Return View(Manager.GetViewModel())
End If
Return New MyRedirect(model.URL)
End Function
Public Function SetCulture(culture As String, returnUrl As String) As ActionResult
Response.Cookies.Add(New HttpCookie("culture") With {
.Value = culture,
.Expires = DateTime.Now.AddYears(1)
})
Return Redirect(returnUrl)
End Function
Protected Overrides Sub ExecuteCore()
Dim cultureName = "en-US"
Dim cultureCookie = Request.Cookies("culture")
If (cultureCookie IsNot Nothing) Then
cultureName = Request.Cookies("culture").Value
End If
Threading.Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(cultureName)
Threading.Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture(cultureName)
MyBase.ExecuteCore()
End Sub
Protected Overrides Sub OnActionExecuting(filterContext As System.Web.Mvc.ActionExecutingContext)
MyBase.OnActionExecuting(filterContext)
Dim controller = filterContext.RouteData.Values("controller").ToString
Dim action = filterContext.RouteData.Values("action").ToString
If (action.ToLower = "enterclaim" OrElse action.ToLower = "changeclaim") Then
Return
Else
Dim claimNumber As String = String.Empty
Dim workerID As Decimal
If (Session("ClaimNumber") IsNot Nothing) Then
claimNumber = Session("ClaimNumber").ToString
End If
If (Session("WorkerID") IsNot Nothing) Then
workerID = CDec(Session("WorkerID"))
End If
If (String.IsNullOrEmpty(claimNumber)) Then
If (workerID = 0) Then
If (Manager.IsExternalUser) Then
workerID = Manager.GetWorkerIdByDomainUser
claimNumber = Manager.GetMostRecentClaimNumber(workerID)
Else
filterContext.Result = New RedirectResult("/MyClaim/Home/EnterClaim")
End If
End If
End If
Manager.SetClaimNumber(claimNumber)
End If
End Sub
Public Function SendMessage(<Bind(prefix:="SendMessage")> model As IWSendMessageViewModel) As ActionResult
Manager.SendAdjusterEmail(model.AdjusterEmail, model.PersonEmail, "IW Contact Message", model.Message, model.SendCopyToSender)
Return Json(New With {.message = "Success"}, "application/json")
End Function
End Class
End Namespace
答案 0 :(得分:2)
对于控制器动作来说,这绝对太过分了。 If (Not securityToken.ConflictAccess)
之类的内容应该放入您的控制器操作应该使用的自定义Authorize
属性中。 ModelState.AddModelError("ClaimNumber", "Invalid claim number.")
之类的内容会进入自定义验证属性,或者如果您在模型的FV验证程序中使用FluentValidation.NET(我强烈建议您这样做)。
这样的事情:
If (model.URL.Contains("ChangeClaim") OrElse model.URL.Contains("EnterClaim")) Then
model.URL = Url.Action("Index", "Home")
End If
可以进入您将返回的自定义操作结果。
就视图中的条件逻辑而言,它很好。您可以使用视图模型属性来显示/隐藏某些UI元素。显然,应该在相应的控制器操作中进行适当的授权(通过自定义授权属性),因为您隐藏了用户链接的事实并不意味着恶意用户无法伪造请求并且仍然能够调用您的控制器动作。