我有一个控制器,它有方法GetSignatories(),AddMe(),RemoveMe(),AddUser(),RemoveUser()以及更多内容我必须验证每次合同是否存在,如果用户如果所请求的版本存在,则可以访问合同。我想知道我应该把这段代码放在哪里?在服务中还是在我的控制器的其他方法中提取?我的问题是我soometime返回Unathorized或NotFound并且不知道什么是最好的方法。
这是我的控制器:
public partial class ContractController : Controller
{
private ISession _session;
private IAuthenticationService _authService;
public V1Controller(ISession session, IAuthenticationService authService)
{
_session = session;
_authService = authService;
}
[HttpPost]
[Authorize(Roles = "User")]
[ValidateAntiForgeryToken]
public virtual ActionResult GetSignatories(string contractId, int version)
{
//NOTE Should be extracted
var contract = _session.Single<Contract>(contractId);
if (contract == null) return HttpNotFound();
var user = _authService.LoggedUser();
if (contract.CreatedBy == null || !contract.CreatedBy.Id.HasValue || contract.CreatedBy.Id.Value != user.Id) return new HttpUnauthorizedResult();
if (contract.Versions.Count < version) return HttpNotFound();
/*NOTE END Should be extracted */
return Json(contract.CurrentVersion.Tokens.Select(x => x.User).ToList());
}
[HttpPost]
[Authorize(Roles = "User")]
[ValidateAntiForgeryToken]
public virtual ActionResult AddMe(string contractId, int version)
{
//NOTE Should be extracted
var contract = _session.Single<Contract>(contractId);
if (contract == null) return HttpNotFound();
var user = _authService.LoggedUser();
if (contract.CreatedBy == null || !contract.CreatedBy.Id.HasValue || contract.CreatedBy.Id.Value != user.Id) return new HttpUnauthorizedResult();
if (contract.Versions.Count < version) return HttpNotFound();
/*NOTE END Should be extracted */
return AddUserToContract(contract, new UserSummary(user));
}
[HttpPost]
[Authorize(Roles = "User")]
[ValidateAntiForgeryToken]
public virtual ActionResult RemoveMe(string contractId, int version)
{
//NOTE Should be extracted
var contract = _session.Single<Contract>(contractId);
if (contract == null) return HttpNotFound();
var user = _authService.LoggedUser();
if (contract.CreatedBy == null || !contract.CreatedBy.Id.HasValue || contract.CreatedBy.Id.Value != user.Id) return new HttpUnauthorizedResult();
if (contract.Versions.Count < version) return HttpNotFound();
/*NOTE END Should be extracted */
return RemoveUserFromContract(contract, new UserSummary(user));
}
[HttpPost]
[Authorize(Roles = "User")]
[ValidateAntiForgeryToken]
public virtual ActionResult AddUser(string contractId, int version, UserSummary userSummary)
{
//NOTE Should be extracted
var contract = _session.Single<Contract>(contractId);
if (contract == null) return HttpNotFound();
var user = _authService.LoggedUser();
if (contract.CreatedBy == null || !contract.CreatedBy.Id.HasValue || contract.CreatedBy.Id.Value != user.Id) return new HttpUnauthorizedResult();
if (contract.Versions.Count < version) return HttpNotFound();
/*NOTE END Should be extracted */
return AddUserToContract(contract, userSummary);
}
[HttpPost]
[Authorize(Roles = "User")]
[ValidateAntiForgeryToken]
public virtual ActionResult RemoveUser(string contractId, int version, UserSummary userSummary)
{
//NOTE Should be extracted
var contract = _session.Single<Contract>(contractId);
if (contract == null) return HttpNotFound();
var user = _authService.LoggedUser();
if (contract.CreatedBy == null || !contract.CreatedBy.Id.HasValue || contract.CreatedBy.Id.Value != user.Id) return new HttpUnauthorizedResult();
if (contract.Versions.Count < version) return HttpNotFound();
/*NOTE END Should be extracted */
return RemoveUserFromContract(contract, userSummary);
}
}
对于那些可能正在寻找如何在全球范围内注册模型绑定器的人来说:
public static void RegisterModelBinders()
{
var session = (ISession)DependencyResolver.Current.GetService(typeof(ISession));
var authService = (IAuthenticationService)DependencyResolver.Current.GetService(typeof(IAuthenticationService));
System.Web.Mvc.ModelBinders.Binders[typeof (Contract)] = new ContractModelBinder(session, authService);
}
答案 0 :(得分:2)
确实你有相当重复的代码。有很多方法可以重构此代码,其中一种方法包括为Contract
模型编写自定义模型绑定器:
public class ContractModelBinder : DefaultModelBinder
{
private readonly ISession _session;
private readonly IAuthenticationService _authService;
public ContractModelBinder(ISession session, IAuthenticationService authService)
{
_session = session;
_authService = authService;
}
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
string contractId = null;
int version = 0;
var contractIdValue = bindingContext.ValueProvider.GetValue("contractId");
var versionValue = bindingContext.ValueProvider.GetValue("version");
if (versionValue != null)
{
version = int.Parse(versionValue.AttemptedValue);
}
if (contractIdValue != null)
{
contractId = contractIdValue.AttemptedValue;
}
var contract = _session.Single<Contract>(contractId);
if (contract == null)
{
throw new HttpException(404, "Not found");
}
var user = _authService.LoggedUser();
if (contract.CreatedBy == null ||
!contract.CreatedBy.Id.HasValue ||
contract.CreatedBy.Id.Value != user.Id
)
{
throw new HttpException(401, "Unauthorized");
}
if (contract.Versions.Count < version)
{
throw new HttpException(404, "Not found");
}
return contract;
}
}
在Contract
中使用Application_Start
模型注册此模型活页夹后,您的控制器就会变为:
public class ContractController : Controller
{
[HttpPost]
[Authorize(Roles = "User")]
[ValidateAntiForgeryToken]
public ActionResult GetSignatories(Contract contract)
{
return Json(contract.CurrentVersion.Tokens.Select(x => x.User).ToList());
}
[HttpPost]
[Authorize(Roles = "User")]
[ValidateAntiForgeryToken]
public ActionResult AddMe(Contract contract)
{
var user = contract.CreatedBy;
return AddUserToContract(contract, new UserSummary(user));
}
[HttpPost]
[Authorize(Roles = "User")]
[ValidateAntiForgeryToken]
public ActionResult RemoveMe(Contract contract)
{
var user = contract.CreatedBy;
return RemoveUserFromContract(contract, new UserSummary(user));
}
[HttpPost]
[Authorize(Roles = "User")]
[ValidateAntiForgeryToken]
public ActionResult AddUser(Contract contract, UserSummary userSummary)
{
return AddUserToContract(contract, userSummary);
}
[HttpPost]
[Authorize(Roles = "User")]
[ValidateAntiForgeryToken]
public ActionResult RemoveUser(Contract contract, UserSummary userSummary)
{
return RemoveUserFromContract(contract, userSummary);
}
}
我们成功put it on a diet。
答案 1 :(得分:2)
一种可能的解决方案是创建一个IContractService
接口,该接口有两个方法,一个用于获取合同,另一个用于验证合同:
public IContractService
{
Contract GetContract(int id);
ValidationResult ValidateContract(Contract contract);
}
ValidationResult
可以是一个枚举,只是告诉调用者该方法如何继续:
public enum ValidationResult
{
Valid,
Unauthorized,
NotFound
}
IContractService
的可能实施:
public class ContractService : IContractService
{
private readonly ISession _session;
private readonly IAuthenticationService _authService;
// Use Dependency Injection for this!
public ContractService(ISession session, IAuthenticationService authService)
{
_session = session;
_authService = authService;
}
public Contract GetContract(int id)
{
var contract = _session.Single<Contract>(contractId);
// hanlde somwhere else whether it's null or not
return contract;
}
public ValidationResult ValidateContract(Contract contract)
{
var user = _authService.LoggedUser();
if (contract.CreatedBy == null || !contract.CreatedBy.Id.HasValue ||
contract.CreatedBy.Id.Value != user.Id)
return ValidationResult.Unauthorized;
if (contract.Versions.Count < version)
return ValidationResult.NotFound;
return ValidationResult.Valid;
}
}
然后在您的控制器中,您仍然可以将各种HttpNotFound
等返回到视图中:
[HttpPost, Authorize(Roles = "User"), ValidateAntiForgeryToken]
public virtual ActionResult GetSignatories(string contractId, int version)
{
//NOTE Should be extracted
var contract = _contractService.GetContract(contractId);
if (contract == null)
return HttpNotFound();
var result = _contractService.ValidateContract(contract);
if (result == ValidationResult.Unauthorized)
return new HttpUnauthorizedResult();
if (result == ValidationResult.NotFound)
return HttpNotFound();
return Json(contract.CurrentVersion.Tokens.Select(x => x.User).ToList());
}