i have an object "ApplicantDetail" with list of objects in ApplicantController and i want to send Post Request to Personaldetails Api On To save into database and get response back
Api On ApplicantController
// POST: api/ApplicantDetail
[HttpPost]
[Route("~/api/ApplicantDetail")]
public IActionResult Post([FromBody] Personaldetail ApplicantDetail)
{
Personaldetail personaldetail = new Personaldetail
{
Name = ApplicantDetail.Name,
Cnic = ApplicantDetail.Cnic,
Phone = ApplicantDetail.Phone
};
List<Address> addresses = new List<Address>();
List<Employee> employees = new List<Employee>();
List<Bank> banks = new List<Bank>();
addresses.AddRange(ApplicantDetail.Address);
employees.AddRange(ApplicantDetail.Employee);
banks.AddRange(ApplicantDetail.Bank);
var response = *//How to Call Personaldetail Post APi of PersonaldetailController Controller From Here and Get
response back//*
return null;
}
Api On Personaldetail Controller
// POST: api/Personaldetails
[HttpPost]
public async Task<IActionResult> PostPersonaldetail([FromBody] Personaldetail personaldetail)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
_context.Personaldetail.Add(personaldetail);
await _context.SaveChangesAsync();
return CreatedAtAction("GetPersonaldetail", new { id = personaldetail.ApplicantId }, personaldetail);
}
You should create a service class to represent the personal details API. In this class, you would inject HttpClient, and then set up IHttpClientFactory with a strongly-typed client:
public class PersonalDetailsService
{
private readonly HttpClient _client;
public PersonalDetailsService(HttpClient client)
{
_client = client;
}
// methods here to interact with API via `_client`
}
Then, in ConfigureServices:
services.AddHttpClient<PersonalDetailsService>(c =>
{
c.BaseAddress = new Uri(Configuration["PersonalDetailsAPIUrl"]);
// configure anything else you need to on the `HttpClient`
});
Finally, in your controller, you inject PersonalDetailsService:
[ApiController]
[Route("api/ApplicantDetail")]
public class ApplicantController
{
private readonly PersonalDetailsService _personalDetailsService;
public ApplicantController(PersonalDetailsService personalDetailsService)
{
_personalDetailsService = personalDetailsService;
}
[HttpPost("")]
public async Task<IActionResult> Post([FromBody] Personaldetail ApplicantDetail)
{
...
var response = await _personalDetailsService.SomeMethodAsync(someParam);
return null;
}
}
If this is within the same process it's unwise to call a controller from another controller.
It's more common to create a class, usually called a service, in which you put your logic to apply the task at hand.
This will have some benifits:
isolation of the logic
not having to worry about it when changing one endpoint
not worry about changing url's or authentication
not having an unnecessary network action
E.g.:
The service:
public class YourService
{
public void YourMethod(parameters)
{
//do your stuff
}
}
The usage:
public class Controller1 : Controller
{
public void YourAction1()
{
//controller specific stuff like model validation
//shared logic
var service = new YourService();
service.YourMethod();
}
}
public class Controller2 : Controller
{
public void YourAction2()
{
//controller specific stuff like model validation
//shared logic
var service = new YourService();
service.YourMethod();
}
}
Alternativly you can use a DI framework to resolve your service.
I could see that your target method (PostPersonaldetail) on controller2 (Personaldetail Controller) is an asynchronous method. While we are calling it we need to use the await keyword with async applied to the method (POST: api/ApplicantDetail) as we can't use await keyword in a method with out making the method as async. Alternatively we can apply wait on the method call too.
Controllers are nothing but classes, we can create an instance and call methods defined in it, however it's not a good practice. Using dependency injection we can get references to other services/controllers with in the application and use it to call methods defined on them.
Approach 1:
public async IActionResult Post([FromBody] Personaldetail ApplicantDetail)
{
var response = await new controller2().PostPersonaldetail(persondetails);
}
Approach 2:
public IActionResult Post([FromBody] Personaldetail ApplicantDetail)
{
var response = new controller2().PostPersonaldetail(persondetails).Wait();
}
The following links can be helpful.
Resource 1
Resource 2
I don't think you want to new up an instance because it could be missing dependencies. You can do something like:
var controller = DependencyResolver.Current.GetService<PostPersonaldetail>();
controller.ControllerContext = new ControllerContext(this.Request.RequestContext, controller);
Then make the call.
You could also use dependency injection and just have a reference in the controller:
class ApplicantController : ControllerBase
{
public ApplicantController(ControllerB controllerb)
{
_contollerB = controllerB;
}
you may have to add a call to add the transient service:
services.AddTransient<ControllerB>();
Related
I have an api client that in its constructor accepts access token
public class ApiClient : IApiClient
{
public ApiClient(string accessToken)
}
To get that api token I need to create instance of another class and call method GetTokenAsync()
public class TokenClient
{
public Task<string> GetTokenAsync();
}
now I want to inject IApiClient to my TestService
public class TestService
{
public TestService(IApiClient client)
}
However it is not possible register instance in this way
services.AddScoped<IApiClient,ApiClient>(async x=>
{
tokenClient = x.GetService<TokenClient>();
var token = await tokenClient.GetTokenAsync();
return new ApiClient(token);
}
to overcome that I have created ApiClientProvider class
public class ApiClientProvider()
{
public async Task<IApiClient> GetClientAsync()
{
tokenClient = x.GetService<TokenClient>();
var token = await tokenClient.GetTokenAsync();
return new ApiClient(token);
}
}
and now I inject it to TestService
but in every method I have to use
IApiClient apiClient= await _apiClientProvider.GetClientAsync();
I don not like this code, I prefer when dependencies are injected and not resolved in every function, however I do not see any way around. Can you advise if this can be moved to registration or maybe it shouldn't go there.
You should change your design slightly.
Rather than inject a string into your ApiClient, inject an ITokenClient:
public interface ITokenClient
{
Task<string> GetTokenAsync();
}
public class TokenClient : ITokenClient
{
public Task<string> GetTokenAsync() { }
}
public class ApiClient : IApiClient
{
readonly Task<string> tokenTask;
public ApiClient(ITokenClient tokenClient)
{
// Initiate the token request on construction
tokenTask = tokenClient.GetTokenAsync();
}
public async Task SomeMethod()
{
string token = await tokenTask;
// Use your token..
}
}
Any methods that rely on the token must be async, but as your calling an API they're likely to be async anyway.
Using this method, you simply need to register your clients with the container and no factories / provider types are required.
In ASP.NET Core we can register all dependencies during start up, which executed when application starts. Then registered dependencies will be injected in controller constructor.
public class ReportController
{
private IReportFactory _reportFactory;
public ReportController(IReportFactory reportFactory)
{
_reportFactory = reportFactory;
}
public IActionResult Get()
{
vart report = _reportFactory.Create();
return Ok(report);
}
}
Now I want to inject different implementations of IReportFactory based on data in current request (User authorization level or some value in the querystring passed with an request).
Question: is there any built-in abstraction(middleware) in ASP.NET Core where we can register another implementation of interface?
What is the possible approach for this if there no built-in features?
Update
IReportFactory interface was used as a simple example. Actually I have bunch of low level interfaces injected in different places. And now I want that different implementation of those low level interfaces will be injected based on request data.
public class OrderController
{
private IOrderService _orderService;
public OrderController(IOrderService orderService)
{
_orderService = orderService;
}
public IActionResult Create()
{
var order = _orderService.Create();
return Ok(order);
}
}
public class OrderService
{
private OrderBuilder _orderBuilder;
private IShippingService _shippingService; // This now have many different implementations
public OrderService(
OrderBuilder _orderBuilder,
IShippingService _shippingService)
{
_orderService = orderService;
_shippingService = shippingService;
}
public Order Create()
{
var order = _orderBuilder.Build();
var order.ShippingInfo = _shippingService.Ship();
return order;
}
}
Because we know which implementation we need to use on entry point of our application (I think controller action can be considered as entry point of application), we want inject correct implementation already there - no changes required in already existed design.
No, you can't. The IServiceCollection is populated during application startup and built before Configure method is called. After that (container being built), the registrations can't be changed anymore.
You can however implement an abstract factory, be it as factory method or as an interface/class.
// Its required to register the IHttpContextAccessor first
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddScoped<IReportService>(provider => {
var httpContext = provider.GetRequired<IHttpContextAccessor>().HttpContext;
if(httpContext.User.IsAuthorized)
{
return new AuthorizedUserReportService(...);
// or resolve it provider.GetService<AuthorizedUserReportService>()
}
return new AnonymousUserReportService(...);
// or resolve it provider.GetService<AnonymousUserReportService>()
});
Alternatively use an abstract factory class
I'm afraid you can not directly acheive the goal via simple dependency injection , as the the dependency injection configured at Startup stage , in other words , all services and implementions has been configured before a request comming .
However , you can inject a Create Service delegate so that can we create the required service implemention instance in runtime .
For instance , if we have a IReportFactory Interface and two implementions as blew :
public interface IReportFactory
{
object Create();
}
public class ReportFactory1 : IReportFactory
{
public object Create()
{
return new { F = 1, };
}
}
public class ReportFactory2 : IReportFactory {
public object Create()
{
return new { F = 2, };
}
}
As we want to get the required implemention in future , we need to register the Implementions first .
services.AddScoped<ReportFactory1>();
services.AddScoped<ReportFactory2>();
and here's where the magic happens :
We don't register a IReportFactory
We just add a Func<HttpContext,IReportFactory> instead , which is a CreateReportFactoryDelegate
public delegate IReportFactory CreateReportFactoryDelegate(Microsoft.AspNetCore.Http.HttpContext context);
We need add the CreateReportFactoryDelegate to servies too.
services.AddScoped<CreateReportFactoryDelegate>(sp => {
// return the required implemention service by the context;
return context => {
// now we have the http context ,
// we can decide which factory implemention should be returned;
// ...
if (context.Request.Path.ToString().Contains("factory1")) {
return sp.GetRequiredService<ReportFactory1>();
}
return sp.GetRequiredService<ReportFactory2>();
};
});
Now , we can inject a CreateReportFactoryDelegate into controller :
public class HomeController : Controller
{
private CreateReportFactoryDelegate _createReportFactoryDelegate;
public HomeController(CreateReportFactoryDelegate createDelegate) {
this._createReportFactoryDelegate = createDelegate;
// ...
}
public async Task<IActionResult> CacheGetOrCreateAsync() {
IReportFactory reportFactory = this._createReportFactoryDelegate(this.HttpContext);
var x=reportFactory.Create();
// ...
return View("Cache", cacheEntry);
}
}
It is possible by using the HttpContextAccessor in Startup.cs
services.AddHttpContextAccessor();
services.AddScoped<IYourService>(provider =>
{
var contextAccessor = provider.GetService<IHttpContextAccessor>();
var httpContext = contextAccessor.HttpContext;
var contextVariable = httpContext. ...
// Return implementation of IYourService that corresponds to your contextVariable
});
Expanding on #JohanP comment about using IEnumerable
//Program.cs
//get the builder
var builder = WebApplication.CreateBuilder(args);
//register each type
builder.Services.AddScoped<IReport,Report1>();
builder.Services.AddScoped<IReport,Report2>();
builder.Services.AddScoped<IReport,Report3>();
//register the factory class
builder.Services.AddScoped<IReportFactory,ReportFactory>();
//IReport Interface
public interface IReport
{
string ReportType{ get; set; }
}
//ReportFactory.cs
public class ReportFactory : IReportFactory
{
private IEnumerable<IReport> _handlers;
//ctor
public ReportFactory(IEnumerable<IReport> handlers)
=> _handlers = handlers;
internal IReport? Creat(string reportType) =>
_handlers.Where(h => h.ReportType== reportType).First();
}
//Controller
public class ReportController
{
private IReportFactory _reportFactory;
public ReportController(IReportFactory reportFactory)
{
_reportFactory = reportFactory;
}
//modify to your project needs
public IActionResult Get([FromBody] string reportType)
{
if (HttpContext.User.IsAuthorized)
{
var report = _reportFactory.Create(reportType);
return Ok(report);
}
}
}
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.
I've got a base ApiController for my controllers to inherit:
public BaseApiController(ILogger logger) : ApiController
{
private readonly ILogger _logger;
public BaseApiController(ILogger logger)
{
_logger = logger.ForContext("SomeContext");
}
}
And a simple controller that's inheriting from the base controller:
public SomeController : BaseApiController
{
public SomeController(ILogger logger) : base(logger)
{ }
public IHttpActionResult SomeAction()
{
_logger.Information("Start doing something...");
//Do stuff...
_logger.Information("End doing something...");
return Ok();
}
}
I've created a simple test for the controller using Xunit and Nsubstitute:
public void SomeAction_ReturnsOk()
{
//Arrange
var logger = Substitute.For<ILogger>();
var controller = new SomeController(logger) {
Request = Substitute.For<HttpRequestMessage>()
};
//Act
var result = controller.SomeAction();
//Assert
logger.ReceivedWithAnyArgs().Information(Arg.Any<string>());
}
When executing the test case, it fails stating that it has received zero calls to the logger.Information() method. When debugging the _receivedCalls property (on the substituted ILogger), if the debug context is within the test case itself it is showing a single call to the logger.ForContext() method (which was called on the base class constructor), however when looking at the debug within the context of the controller.SomeAction() method, the same _receivedCalls property shows the two calls to logger.Information() as would be expected but not the call to ForContext().
So it appears to me that for some reason Nsubstitute is creating two separate instances of the substitute class, one in the context of the base controller and one in the actual controller - why is this and how can I avoid it?
You need to stub the ForContext return like this:
public void SomeAction_ReturnsOk()
{
//Arrange
var logger = Substitute.For<ILogger>();
logger.ForContext(Arg.Any<string>()).Returns(logger);
var controller = new SomeController(logger) {
Request = Substitute.For<HttpRequestMessage>()
};
//Act
var result = controller.SomeAction();
//Assert
logger.Received().Information(Arg.Any<string>());
}
I change the assert to:
logger.Received().Information(Arg.Any<string>());
OR:
logger.ReceivedWithAnyArgs().Information("");
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.