所以我创建了一个提供程序来处理我的所有代码。 最初它看起来像这样:
public class AnswerProvider : ApiController
{
private readonly IUnitOfWork _unitOfWork;
private readonly AnswerService _answerService;
private QuestionService _questionService;
public QuestionService QuestionService => _questionService ?? (_questionService = new QuestionService(this._unitOfWork));
public AnswerProvider(IUnitOfWork unitOfWork)
{
this._unitOfWork = unitOfWork;
this._answerService = new AnswerService(unitOfWork);
}
public async Task<IHttpActionResult> CreateAsync(AnswerRequestModel model)
{
try
{
// Validate our answer count
await ValidateAnswerCountAsync(model.QuestionId);
// Create our model
var answer = ModelFactory.Create(model);
// Add our images to our answer
answer.Images = model.Images;
// Save our model
this._answerService.Create(answer);
// Save the database changes
await this._unitOfWork.SaveChangesAsync();
// Return our updated model
return Ok(ModelFactory.Create(answer));
// If there is an error
}
catch (Exception ex)
{
// Return our error
return BadRequest(ex.Message.ToString());
}
}
/// <summary>
/// Validates the answers based on the question type
/// </summary>
/// <param name="id">The id of the question</param>
/// <returns></returns>
private async Task ValidateAnswerCountAsync(int id)
{
// Get our question
var question = await this.QuestionService.GetAsync(id, "Answers");
// If we have 3 answers or more
if (question.Answers.Count >= 3 && question.Type == QuestionType.Boolean)
{
// Throw an error
throw new InvalidOperationException("A Boolean question can only have 3 answers");
}
}
}
我继承了ApiController,因为我希望能够访问 Ok , BadRequest 和其他此类方法,这是唯一的原因。 当我尝试运行该代码时,即使它编译我也会收到此错误:
HttpControllerContext.Configuration不能为null
我认为这是因为我试图继承 ApiController 而我不应该这样做。 有没有其他方法可以访问 Ok 和其他类似的方法而不继承 ApiController 。 请记住,我将有多个提供商。
答案 0 :(得分:0)
不要从ApiController继承,因为它是由请求管道中的工厂实例化的。您应该只为实际的api控制器实例继承它,而不是为了方便某些现有方法。最好的解决方案是在您的Provider / Service /中抛出自定义异常,并在控制器中捕获它们并返回正确的HttpStatus或让异常通过,这将导致500状态。
尽管如此我已经在ApiController周围创建了一个小包装器,您可以在基于接口的Provider / Service / etc中重用它(因此很容易抽象出来并且易于测试)。
// demo of controller calling your Provider
public class SomeController : ApiController
{
public async Task<IHttpActionResult> Get()
{
var wrapper = this.ActionWrapper();
var answerProvider = new AnswerProvider(wrapper);
var result = await answerProvider.CreateAsync(model);
}
}
// a simple extension on the ApiController
public static class WrapperExtension
{
public static IActionWrapper ActionWrapper(this ApiController controller)
{
return new ApiActionWrapperContext(controller);
}
}
// wrapped in interface so its easy to unit test the Provider
public interface IActionWrapper
{
OkResult Ok();
BadRequestResult BadRequest();
BadRequestErrorMessageResult BadRequest(string message);
OkNegotiatedContentResult<T> Ok<T>(T content);
}
// the implementation, this takes the current Controller and uses it as the context to return the same result types
// only implemented Ok and BadRequest as a demo, you can extend it as needed
public class ApiActionWrapperContext : IActionWrapper
{
private ApiController _controller;
public ApiActionWrapperContext(ApiController controller)
{
_controller = controller;
}
public BadRequestResult BadRequest()
{
return new BadRequestResult(_controller);
}
public BadRequestErrorMessageResult BadRequest(string message)
{
return new BadRequestErrorMessageResult(message, _controller);
}
public OkResult Ok()
{
return new OkResult(_controller);
}
public OkNegotiatedContentResult<T> Ok<T>(T content)
{
return new OkNegotiatedContentResult<T>(content, _controller);
}
}
// provider shortered with just some relevant code to demo
// notice constructor, the new private field, and the use of it
public class AnswerProvider
{
private IActionWrapper _actionWrapper;
public AnswerProvider(IActionWrapper actionWrapper)
{
if(actionWrapper == null)
throw new ArgumentNullException("actionWrapper");
_actionWrapper = actionWrapper;
}
public async Task<IHttpActionResult> CreateAsync(AnswerRequestModel model)
{
try
{
// Validate our answer count
await ValidateAnswerCountAsync(model.QuestionId);
// Create our model
var answer = ModelFactory.Create(model);
// Add our images to our answer
answer.Images = model.Images;
// Save our model
this._answerService.Create(answer);
// Save the database changes
await this._unitOfWork.SaveChangesAsync();
// Return our updated model
return this._actionWrapper.Ok(ModelFactory.Create(answer));
// If there is an error
}
catch (Exception ex)
{
// Return our error
return this._actionWrapper.BadRequest(ex.Message.ToString());
}
}
}