call another api controller - c#

When I call user controller (api/user), I am able to pass user credentials, however the application crashes with null exception error (Value cannot be null) in the values controller:
public class ValuesController : ApiController
{
private cdwEntities db = new cdwEntities();
public HttpResponseMessage Get([FromUri] Query query)
{
var data = db.database.AsQueryable();
if (query.name != null)
{
data = data.Where(c => c.Name == query.name);
}
if (query.price != null)
{
data = data.Where(c => c.Price == query.price);
}
if (!data.Any())
{
var message = string.Format("error");
return Request.CreateErrorResponse(HttpStatusCode.NotFound, message);
}
***return Request.CreateResponse(HttpStatusCode.OK, data);***
}
}
I believe this error is because valuescontroller method cannot pass null values as it always pass parameters(i.e. api/values/name=tom), hence when I call user controller, it throws null error because the system has not passed any parameters into the Valuescontroller from user controller.
public class UserController : ApiController
{
[Authorize]
public HttpResponseMessage Get([FromUri] Query query)
{
if (User.IsInRole("user"))
{
var result = new itemController();
return result.Get(query);
}
var message = string.Format("No data was found");
return Request.CreateErrorResponse(HttpStatusCode.NotFound, message);
}
}
Is their some built-in function i could use to solve this issue or any framework/library i should look into?
Many thanks for your help and time.

Others have pointed out that you should not often (ever?) call one view controller endpoint from another, but in the case that you need/want to, you need to be sure the target has been initialized properly. This is done using ControllerBuilder.
So instead of:
var result = new itemController();
return result.Get(query); // this will blow up!
You would do:
IControllerFactory factory = ControllerBuilder.Current.GetControllerFactory();
itemController c = (itemController) factory.CreateController(
ControllerContext.RequestContext, "item");
return c.Get(query);
This will ensure that the target view controller has been initialized with all necessary context.

You should not call one API endpoint method from other API endpoint. Instead you need to have proper segregation of code between API, Business Logic Layer and Data Access Layer. I would do it in following way -
API -
public class UserController : ApiController
{
[Authorize]
public HttpResponseMessage Get([FromUri] Query query)
{
BusinessLayer layer = new BusinessLayer();
if (User.IsInRole("user"))
{
var result = layer.GetData(query);
// use result here and return HttpResponseMessage
var message = string.Format("No data was found");
return Request.CreateErrorResponse(HttpStatusCode.NotFound, message);
}
}
}
And in your business logic layer -
public ResultModel Get(Query query)
{
// Process your model Query here... and then return some meaningful result here...
// Also call Data Access Layer Methods from here, instead of making direct database
// (entity framework) calls...
}
For better flexible and loosely coupled systems, you need to have Dependency Injection (probably using Unity, but there are many other options like Autofac, Ninject etc.)

Related

Create an IEnumerable<AbstractClass> of specific instances from different classes all inheriting from the abstract class

I have controllers which, for the sake of backwards compatibility, only have one action. The JSON request comes with an attribute "type" which determines what the action should do with it.
My idea for a clean solution was to build a set of action handlers. They all inherit from an abstract class called ActionHandler which has two methods
public abstract bool CanHandle(ClientRequest request);
and
public abstract object Handle(dynamic request)
And it has a property
public abstract string ActionForController { get; }
in which the specific actionhandlers just return the name of the controller they want to handle for. This is not very important, but may help clarify something later.
The controller is inserted with an ActionHandlerRegister which has an IEnumerable and a method "GetActionHandler". It returns the first specific ActionHandler that can handle the request.
public ActionHandler GetActionHandler(ClientRequest request)
{
foreach(var actionHandler in ActionHandlers)
{
if (actionHandler.CanHandle(request))
{
return actionHandler;
}
}
throw new BadRequestException(string.Format(CultureInfo.InvariantCulture, BadRequestExceptionTemplate, request.Type));
}
The controllers look like this:
public class LogController : ControllerBase
{
private readonly IActionHandlerRegister<LogController> logHandlers;
public LogController(IActionHandlerRegister<LogController> logHandlers)
{
this.logHandlers = logHandlers ?? throw new ArgumentNullException(nameof(logHandlers));
}
[HttpPost]
public async Task<IActionResult> Post([FromBody] dynamic rawJson)
{
var jsonBody = ((JsonElement)rawJson).ToString();
if (string.IsNullOrEmpty(jsonBody))
{
return BadRequest(ActionHandler.BadRequestRequestNullOrTypeMissingError);
}
var clientRequest = JsonSerializer.Deserialize<ClientRequest>(jsonBody);
if (clientRequest == null || string.IsNullOrEmpty(clientRequest.Type))
{
return BadRequest(ActionHandler.BadRequestRequestNullOrTypeMissingError);
}
try
{
var handler = logHandlers.GetActionHandler(clientRequest);
var result = handler.Handle(rawJson);
return Ok(result);
}
catch (BadRequestException ex)
{
return BadRequest(ex.Message);
}
}
}
For people paying attention: yes, I'm passing the rawjson to handler.Handle. This is because "ClientRequest" is something generic (from which I can read the type) but the handler needs the specific request, so it's deserializing again to something more specific. Maybe there are better solutions for that. Feel free to tell me.
In startup.cs, the insertion of the ActionHandlerRegister into the controller looks like this:
public void RegisterActionHandlersAsSingleton(IServiceCollection services)
{
IEnumerable<ActionHandler> listOfActionHandlers =
from domainAssembly in AppDomain.CurrentDomain.GetAssemblies()
from actionHandlerType in domainAssembly.GetTypes()
where actionHandlerType.IsAssignableFrom(typeof(ActionHandler))
select (ActionHandler)Activator.CreateInstance(actionHandlerType);
services.AddSingleton<IActionHandlerRegister<LogController>>(new ActionHandlerRegister<LogController>(listOfActionHandlers.Where(a => a.ActionForController == nameof(LogController))));
// other controllers ...
}
You might be able to guess, this last piece of code crashes at runtime telling me it's unable to cast to ActionHandler.
System.InvalidCastException: Unable to cast object of type
'System.Object' to type
'TcServerModules.ActionHandlers.ActionHandler'.
I have been playing around with different solutions, but none of them scratch that itch. What would be a nice, true-to OO-design principle

Unit testing the code that is written using repository pattern

I am implemented my business logic using repository pattern. I basically have Approve method in my controller . I am calling the service method ApproveUserChangeRequest
which in turn invokes GetUserChangeRequest and ApproveUserChangeRequest in the UnitofWork class. I would like to know if this is standard or better way of doing it
Please bare in mind in to test the service methods
UserConroller
[HttpPost]
[AllowAnonymous]
[Route("approve-change-request")]
public IActionResult ApproveUserChangeRequest([FromBody] ApproveUserChangeRequests approveUserChangeRequests)
{
if (!ModelState.IsValid)
{
return BadRequest(new ResponseModel()
{
ResponseMessages = new Dictionary<string, string[]>
{
{ "Errors", ModelState.Values.SelectMany(x => x.Errors).Select(x => x.ErrorMessage).ToArray() }
}
});
}
var result = _userService.ApproveUserChangeRequest(approveUserChangeRequests);
var message = string.Empty;
if (result.Succeeded)
{
return Ok(new ResponseModel()
{
ResponseMessages = new Dictionary<string, string[]>
{
{ "Info", new string[] { $"True" } }
}
});
}
message = string.Join(";", result.Errors.Select(x => $"Code: {x.Code}. Description: {x.Description}"));
_logger.Error(new IdentityException($"Error approving user change requests. Message: {message}"));
return BadRequest();
}
UserService class
public IdentityResult ApproveUserChangeRequest(ApproveUserChangeRequests approveUserChangeRequests)
{
var userChangeRequest = _userUow.GetUserChangeRequest(approveUserChangeRequests.UserChangeRequestID);
IdentityResult result = _userUow.ApproveUserChangeRequest(userChangeRequest, approveUserChangeRequests.ApprovedByAuthUserId, approveUserChangeRequests.AuthApplicationName);
return result;
}
UnitofWork class (uow)
public UserChangeRequest GetUserChangeRequest(int userChangeRequestId)
{
return UserChangeRequestRepository.GetQueryable(x =>
x.Id == userChangeRequestId)
.FirstOrDefault();
}
public IdentityResult ApproveUserChangeRequest(UserChangeRequest userChangeRequest, int approvedByAuthUserId, string authApplicationName)
{
var idResult = IdentityResult.Success;
// Check if UserChangeRequest is still Pending
bool isUserChangeRequestPending = UserChangeRequestRepository.GetQueryable(x => x.Id == userChangeRequest.Id && x.ChangeStatus == "Pending").Any();
if (isUserChangeRequestPending && approvedByAuthUserId > 0)
{
// Inserting record in the UserChangeRequestApproval table
InsertUserChangeRequestApproval(userChangeRequest);
SaveContext();
//Updating the user details in IdentityDB, ClientCompanyContact and AuthUser tables
UpdateUserDetails(userChangeRequest, authApplicationName);
}
else
{
idResult = IdentityResult.Failed(new IdentityError { Description = "No userchange request to approve" });
}
return idResult;
}
It's important to only test each part of your application in isolation. When we test public IActionResult ApproveUserChangeRequest we only want to ensure that it's doing its own job correctly. Anything that it calls should be mocked, and tested separately.
For this you will need to create interfaces for your repository, and your UnitOfWork class. This will allow them to be mocked, and their behaviour simulated.
You should also allow these classes to be injected into the consuming class using Dependency Injection, for example:
private readonly IUserService _userService;
public MyController(IUserService userService)
{
_userService = userService;
}
public IActionResult ApproveUserChangeRequest([FromBody] ApproveUserChangeRequests approveUserChangeRequests)
{
// ... snip
// this now uses the instance that was provided by dependency injection
var result = _userService.ApproveUserChangeRequest(approveUserChangeRequests);
}
You would then be able to test your class/method, whilst mocking the behaviour of your user service. The following example uses Moq, but you could use another mocking framework.
public void ApproveUserChangeRequest_PassesApproveChangeRequestsModelToService()
{
// mock the user service
var userService = new Mock<IUserService>();
// provide the controller with the user service
var controller = new MyController(userService);
// create the model for the request
var model = new ApproveUserChangeRequests();
// test the method
controller.ApproveUserChangeRequest(model);
// make sure that userService.ApproveUserChangeRequest was called with the correct arguments
userService.Verify(u => u.ApproveUserChangeRequest(model));
}
In the unit tests for the Controller, you only need to check that ApproveUserChangeRequest is doing it's job correctly. That is
verifying your model
raising an error if the model isn't valid
calling the user service if it is valid
sending you the correct response if it's successful
logging correctly to your logger
responding with bad request if appropriate
These should all be checked for in separate unit tests.
You should also then write tests for your UserService, and your UnitOfWork class. Only write tests for things that those classes are responsible for. If you find that the class is responsible for too many things, refactor your class until it obeys the single responsibility principle, this will greatly aid your ability to test your code.

How to use FluentValidation in a generic way with DI in MVC controllers

I implemented fluent validation rules. I am sending a request to my controller api endpoint via angular request in json format.
When I receive data and model parameter is populated I want to use fluent validation to validate sent data.
[Route("")]
[HttpPost]
public async Task<IActionResult> Post([FromBody]TesViewModel request)
{
var validator = new TesViewModelValidator();
var result = await validator.ValidateAsync(request);
return Ok();
}
How can I instantiate and access object and pass correct request in generic way with dependency injection?
Create a Base abstraction class:
public abstract class BaseApiRequest
{
}
Inherit your model with this abstraction class
public class YourModel : BaseApiRequest
{
}
After that create an extension method:
public static bool IsValidApiRequest<T>(this T entity)
where T : BaseApiRequest
{
var attribute = (ValidatorAttribute)Attribute.GetCustomAttribute(typeof(T), typeof(ValidatorAttribute));
if (attribute != null)
{
if (entity == null)
return false;
var validator = attribute.ValidatorType;
var instance = Activator.CreateInstance(validator);
MethodInfo method = instance.GetType().GetMethod("Validate", new[] { typeof(T) });
object result = method.Invoke(instance, new object[] { entity });
return (bool)result.GetType().GetProperty("IsValid").GetValue(result); ;
}
return true;
}
Now, you can validate your request using:
if (!request.IsValidApiRequest())
return BadRequest();
I ended up using injecting IValidator instance and invoking it with:
var result = _validator.Validate(instance); where instance is T of registered AbstractValidator

Web Api interaction between multiple controller endpoints

I am looking for a bit of constructive advice. I am trying to map how multiple controller endpoints can interact with each other such that I do not end up writing the same code in multiple controllers. Allow me to illustrate with a simple Kanban example.
I am thinking two(or three) controllers here: BoardController, CardController, SubCardController (undecided). For now let's ignore the fact that cards can be organised into lists, for that we would have a ListController sitting between Board and Card controllers.
Board controller:
public class BoardController : ApiController {
// among basic CRUD methods I have a method that returns single board
// implementation #1
// /api/board/getbyid?id=123
public HttpResponseMessage GetById(int id) {
var board = dataStore.GetById(id);
if (board == null)
return Request.CreateResponse(HttpStatusCode.NotFound);
return Request.CreateResponse(HttpStatusCode.OK, board);
}
// implementation #2
// /api/board/getbyid?id=123
public HttpResponseMessage GetById(int id) {
var board = GetById(id);
if (board == null)
return Request.CreateResponse(HttpStatusCode.NotFound);
return Request.CreateResponse(HttpStatusCode.OK, board);
}
[NonAction]
// normally methods like this one I declare as private
// but in this case CardController needs to call this method as well
public static Board GetById(int id) {
return dataStore.GetById(id);
}
}
Allow me to clarify that dataStore is a reference to another controller that is solely responsible for data access.
Card controller:
public class CardController : ApiController {
// among basic CRUD methods I might want to call BoardControllers GetById(id) method (to verify if board exists for example)
// implementation #1
public HttpResponseMessage GetAll(int boardId) {
// call BoardController.GetById(id) by issueing HTTP request
HttpRequestMessage _request = new HttpRequestMessage(HttpMethod.Get, requestUri);
HttpResponseMessage _response = Client.SendAsync(_request).Result;
Board board = _response.Content.ReadAsAsync<Board>().Result;
if (board == null /* || more condition(s) */)
return Request.CreateResponse(HttpStatusCode.NotFound);
// get cards and return
}
// implementation #2
public HttpResponseMessage GetAll(int boardId) {
// call BoardController.GetById(id) static method
var board = _boardCtrl.GetById(boardId);
if (board == null /* || more condition(s) */)
return Request.CreateResponse(HttpStatusCode.NotFound);
// get cards and return
}
}
That's my two alternative solutions. One one hand implementation #1 does not require additional static methods but on the other, I think it is a bad to issue HTTP requests from one controller action to access another controller action.
Let me know what you guys think. Particularly if there is even more neater alternative.
Create services and inject them into dependent controllers as needed. Controller should be kept lean and not focus on implementation concerns.
public interface IBoardService {
Board GetById(int id);
//...other code removed for brevity
}
public class BoardController : ApiController {
readonly IBoardService dataSource;
public BoardController(IBoardService dataSource) {
this.dataSource = dataSource;
}
// /api/board/getbyid?id=123
public IHttpActionResult GetById(int id) {
var board = dataSource.GetById(id);
return board == null ? NotFound() : OK(board);
}
}
The board service can also be reused to be injected into the CardController if it needs it
public class CardController : ApiController {
readonly IBoardService boardService;
readonly ICardService cardService;
public CardController(ICardService cardService, IBoardService boardService) {
this.cardService = cardService;
this.boardService = boardService;
}
public IHttpActionResult GetAll(int boardId) {
var board = boardService.GetById(boardId);
if (board == null /* || more condition(s) */)
return NotFound();
// get cards from card service and return
}
}
Using the injected service approach allows for it to be reused where needed.
Also, try to keep your controllers lean.
No need for all that logic in the controller.
The implementation of card service can depend on the board service and expose just a GetAllByBoardId(int id) which will reduce the logic in the CardController like in your example.

When to return IHttpActionResult vs Object

In examples of using the ASP.NET Web API I see two different methods used to return data to the calling jQuery function. The first method returns an object of type Client but I am not sure what the second method is returning.
Method #1 (returns Client object)
public IEnumerable<Client> GetAllClients()
{
using (var context = new PQRSModel.PQRSEntities())
{
context.Configuration.ProxyCreationEnabled = false;
var query = context.Clients.OrderBy(c = c.OrgName);
var customers = query.ToList();
return customers;
}
}
Method #2 (What benefit does IHttpActionResult provide?)
public IHttpActionResult GetClient(int clientId)
{
using (var context = new PQRSModel.PQRSEntities())
{
context.Configuration.ProxyCreationEnabled = false;
var client = context.Clients.FirstOrDefault(c = c.ID == clientId);
if (client == null)
{
return NotFound();
}
return Ok(client);
}
}
If the second method finds a single object is there any reason it could not also return a Client object type?
Returning IHttpActionResult provides a nice separation of concerns.
Your controller can focus on responding to the request in the most sensible manner (status codes, error messages, etc.). Another (service) layer can focus on actually retrieving and transforming the business data.
The side-effect is, your controller methods become more unit testable. Consider the following simple example:
public class MyController : ApiController
{
//or better yet, dependency-inject this
SomeService _service = new SomeService();
public IHttpActionResult Get(int id)
{
if (id < 0)
return BadRequest("Some error message");
var data = _service.GetData(id);
if (data == null)
return NotFound();
return Ok(data);
}
}
Not only is this method's logic understandable just by reading it, but you could now test the logic more easily and naturally, something like (using NUnit syntax):
[TestFixture]
public class MyControllerTests
{
[Test]
public void Get_WithIdLessThan0_ReturnsBadRequest()
{
var controller = new MyController();
int id = -1;
IHttpActionResult actionResult = controller.Get(id);
Assert.IsInstanceOf<BadRequestErrorMessageResult>(actionResult);
}
}
Similarly, you could mock the Service layer and test what happens when you give known id parameters to the controller, etc.
Here is a good article on Unit Testing Controllers in Web Api
The second method allows you to return just status codes (like the 404 in the example), streaming file content and other types of non-object content.

Categories

Resources