New Api return Internal Server Error - asp.net-core

I create asp.Net Core API like, after that I create a controller like this:
[Route("api/Email")]
public class EmailController : Controller
{
private readonly IEmailSender _emailSender;
public EmailController(IEmailSender emailSender)
{
_emailSender = emailSender;
}
[Route("Send")]
[HttpPost]
public IActionResult Index(string Email)
{
_emailSender.SendEmailAsync(Email, "Confirm your account","correo desde api");
return View();
}
Problem occcurs when I try to execute this path with Postman as:
http://localhost:3703/api/Email/Send
with JSON raw parameter like:
{
"Email":"myemail#gmail.com"
}
It just returns 500 Internal Server Error, I try to put breakpoint into api Send method and it never hitted. I need to do another configuration to execute a simple method of controller? Regards

Based on the comment to your question the constructor of your controller is not hitted.
So you need to make sure that the IEmailSender is correctly configured for dependency injection.
So in your Startup class go to ConfigureServices method and add the following line if it not exists:
services.AddScoped<IEmailSender, MyEmailSenderImplementation>();
MyEmailSenderImplementation should be the class that impelments IEmailSender interface.

Related

Why does not working version in asp.net core controller

I want to use api version in my .net core project.Then search web and find that's solution.
Even though do exactly all solutions,but I can't get desired result.
So if any can help me,Please show me..
I add Microsoft.AspNetCore.Mvc.Versioning 4.0.0 Package in my project and ..
StartUp.cs
Then in my Controller Add Rout Attribute as Shown :
[ApiController]
[Authorize]
[Route("v{version:apiVersion}/[Controller]")]
[ApiVersion("1.0")]
public class SellerController : Controller
{
private readonly IBus _client;
private readonly string AppBaseUrl = MyHttpContext.AppBaseUrl;
//private readonly IGetUrl _globalUrl;
public SellerController(IBus client/*, IGetUrl globalUrl*/)
{
_client = client;
//_globalUrl = globalUrl;
}
[HttpGet("/Sellers/{SellerId}")] // Dashboard
public async Task<IActionResult> Info(long SellerId)
{
...
}
}
With these code I expected that I can send request to 'Info' method by this url :
But that's not working and get 404 error code status.. when I delete "/v1.0" from url and send request, that's working. I will be glad to help me .. Thanks
In your code, we can find that you applied [HttpGet("/Sellers/{SellerId}")] with route
template begin with / to Info action method, which don't get combined with route templates applied to the controller. To make request to 'Info' method, you could use below URL.
https://localhost:5090/sellers/17
I expected that I can send request to 'Info' method by this url : https://localhost:5090/v1.0/sellers/17
To achieve your requirement, you can try to modify the code like below.
[HttpGet("/v{version:apiVersion}/Sellers/{SellerId}")]
public async Task<IActionResult> Info(long SellerId)
{
//...
//for testing purpose
return Ok(SellerId);
}
Test Result
Update:
If you'd like to include v{version:apiVersion} in route template of controller level attribute routing, you can try to apply [HttpGet("{SellerId}")] to Info action method and make request with https://localhost:5090/v1.0/seller/17.
[ApiController]
[Authorize]
[Route("v{version:apiVersion}/[Controller]")]
[ApiVersion("1.0")]
public class SellerController : Controller
{
[HttpGet("{SellerId}")] // Dashboard
public async Task<IActionResult> Info(long SellerId)
{
//...

How do I get Route attribute to work in .net core api?

So I added a controller to a blank asp.net CORE Api.
public class IsAliveController : ControllerBase
{
[HttpPost]
[HttpGet]
[Route("isalive")]
public object Get()
{
return "I'm alive";
}
}
Then I try to access it via https://localhost:44361/isalive
and I get no response. Do I need to make some modifications to my Startup.cs?
First why have you declared your method both as a get and a post request? you can remove the post attribute.
By default your routing must start with your controller name, add this:
[Route("[controller]")]
[ApiController]
public class IsAliveController : ControllerBase
{
[HttpGet]
public object Get()
{
return "I'm alive";
}
}
Now when you call https://localhost:44361/isalive you will receive the expected response.
There are two solutions to your problem:
#1 Your controller Name is IsAlive and you have added a route attribute on your action method as isAlive, so this would work only if you call using this Url
https://localhost:44361/isalive/isalive
#2 Remove the Route attribute from the action method
public class IsAliveController : ControllerBase
{
[HttpGet]
public object Get()
{
return "I'm alive";
}
}
and you will be able to access using Url
https://localhost:44361/isalive
Found the issue. The template I choose (using Visual studio 2019) was:
Asp.net core web app > Web Application
The startup file in this template is missing a line that I needed to add:
app.UseEndpoints(endpoints =>
{
//Add this line
endpoints.MapControllers();
});
After adding that line the endpoint works without any changes to the controller.

Cannot post JSON to an ASP.NET Core RazorPage handler

I'm working with an ASP.NET Core RazorPage as an alternative to an MVC controller, and I want to be able to submit the client side form via XMLHttpRequest. I've already figured out the XSRF token bits so that passes the muster, but the RazorPages framework doesn't seem to process the inbound JSON payload and bind it to the property as expected.
Some code:
The page's model (.cshtml.cs):
public class IndexModel : PageModel
{
private Database database;
private ILogger logger;
[BindProperty]
public AddRequestModel MyRequest { get; set; }
public IndexModel(Database database, ILogger<IndexModel> logger)
{
this.database = database;
this.logger = logger;
}
public void OnGet() {}
public IActionResult OnPostValidate()
{
if (ModelState.IsValid)
{
// ...
}
return new BadRequestObjectResult(ModelState);
}
public async Task<IActionResult> OnPutConfirmAsync()
{
// ...
}
}
And the client side post:
const url = "?handler=validate";
const data = { MyRequest: this.fields };
await axios.post(url, data);
I have verified the data is being submitted correctly:
That X-XSRF-TOKEN header is being added by axios before the request is submitted. The fact that the server responds with a list of errors indicates that it's not the XSRF token causing the problem:
Note the MyRequest object does not contain the values from the request payload - it was not bound as expected (FirstName would not return a required error otherwise). How can I tell RazorPages to accept the JSON request and bind it to my property?
I was able to get the Binding works by adding FromBody similar to how it worked for ASP.NET Web API 2.
[BindProperty, FromBody]
public BroadcastMessageEditingViewModel BindingInfo { get; set; }
Use urlsearchparams with formdata.
In this post you can find more information How do I post form data with fetch api?
You would be better off posting your data to an API endpoint instead of a page controller. Create a class from ControllerBase and it will handle your JSON post correctly.

How to inject HttpHeader value in controller?

I have Web API developed using ASP.NET Core API. Every incoming request has a custom header value inserted. eg x-correlationid. The controller use this value for logging and tracing the request.
Currently I'm reading the value in each controller as below
[Route("api/[controller]")]
public class DocumentController : Controller
{
private ILogger<TransformController> _logger;
private string _correlationid = null;
public DocumentController(ILogger<DocumentController > logger)
{
_logger = logger;
_correlationid = HttpContext.Request.Headers["x-correlationid"];
}
[HttpPost]
public async Task<intTransform([FromBody]RequestWrapper request)
{
_logger.LogInformation("Start task. CorrelationId:{0}", _correlationid);
// do something here
_logger.LogInformation("End task. CorrelationId:{0}", _correlationid);
return result;
}
}
I think this is against DI rules.
Instead of reading the value inside the controller's constructor, I want to inject the value in the controller's constructor.
Or
Can middleware read the x-correlationid and *somehow* make it available to all the controllers so we don't have to inject it in any controller?
What would be a better option here?
Instead of reading the value inside the controller's constructor, I want to inject the value in the controller's constructor.
You can't inject the value itself into the constructor of the api controller, because at the time of construction the HttpContext is going to be null.
One "injection-style" option would be to use the FromHeaderAttribute in your actions:
[HttpPost]
public async Task<int> Transform(
[FromBody]RequestWrapper request,
[FromHeader(Name="x-correlationid")] string correlationId)
{
return result;
}
Can middleware read the x-correlationid and somehow make it available to all the controllers so we don't have to inject it in any controller?
I think a middleware solution would probably be overkill for what you need. Instead, you can create a custom base class that derives from Controller and have all your Api controllers derive from that.
public class MyControllerBase : Controller
{
protected string CorrelationId =>
HttpContext?.Request.Headers["x-correlationid"] ?? string.Empty;
}
[Route("api/[controller]")]
public class DocumentController : MyControllerBase
{
private ILogger<TransformController> _logger;
public DocumentController(ILogger<DocumentController> logger)
{
_logger = logger;
}
[HttpPost]
public async Task<intTransform([FromBody]RequestWrapper request)
{
_logger.LogInformation($"Start task. CorrelationId:{CorrelationId}");
// do something here
_logger.LogInformation($"End task. CorrelationId:{CorrelationId}");
return result;
}
}
This is what I came up with. I think i can also unit test it.
public interface IRequestContext
{
string CorrelationId { get; }
}
public sealed class RequestContextAdapter : IRequestContext
{
private readonly IHttpContextAccessor _accessor;
public RequestContextAdapter(IHttpContextAccessor accessor)
{
this._accessor = accessor;
}
public string CorrelationId
{
get
{
return this._accessor.HttpContext.Request.Headers[Constants.CORRELATIONID_KEY];
}
}
}
then in startup's configureservice method register the adapter
services.AddSingleton<IRequestContext, RequestContextAdapter>();
and inject it in controller
[Route("api/[controller]")]
public class DocumentController : Controller
{
private ILogger<TransformController> _logger;
private IRequestContext _requestContext = null;
public DocumentController(ILogger<DocumentController > logger,IRequestContext requestContext)
{
_logger = logger;
_requestContext = requestContext;
}
[HttpPost]
public async Task<intTransform([FromBody]RequestWrapper request)
{
_logger.LogInformation("Start task. CorrelationId:{0}", _requestContext.CorrelationId);
// do something here
_logger.LogInformation("End task. CorrelationId:{0}", _requestContext.CorrelationId);
return result;
}
}
Depending on your needs one of following is suitable:
If you need your header values at action level, then using FromHeaderAttribute sounds better (lighter and easier).
If you need to use this header value in lower layers like Repository or DAL, which will be instantiated before Controller has been initialized, then consider to use middleware to get header values initialized and available for other components.

Unable to get Scoped Service in aspnetcore 1 - RC1 to work

My scoped service for some reason seems to be generating different instances of the same class when I try to access it in 2 middlewares within the same request.
Scenario: I am adding a scoped service as such:
public interface ISimplyRecorder
{
void AddInfo(string key, string value);
Dictionary<string, string> GetAllInfo();
}
public class SimplyCoreRecorderService : ISimplyRecorder
{
private Dictionary<string,string> data;
public SimplyCoreRecorderService()
{
data = new Dictionary<string, string>();
}
public void AddInfo(string key,string value)
{
data.Add("",value);
}
public Dictionary<string,string> GetAllInfo()
{
return data;
}
}
and then the following in startup.cs
services.AddScoped<ISimplyRecorder,SimplyRecorderService>();
now I am calling this service in the constructor of a sample Middleware. I am able to access the service with a new instance and add data into it and then I call await _next(context). However, when I am calling the service in my HomeController, MVC which follows the middleware above, I seem to be getting a new instance of the service even though it's the same request.
HomeController:
ISimplyRecorder _simply;
private IHostingEnvironment _env;
public HomeController(IHostingEnvironment env,ISimplyRecorder simply)
{
_simply = simply;
_env = env;
}
public IActionResult Index()
{
_simply.AddInfo("Home:Action","resulted in index action");
return View();
}
complete code available at: https://github.com/muqeet-khan/SimplyCore if someone wants to give it a go.
Middlewares are instantiated only once when it's first involved, then all the following requests are handled by that middleware instance. NOT a new middleware instance for each request.
You get your ISimplyRecorder in the constructor of the middleware and "cache" it as a private readonly variable. This means the middleware will get the ISimplyRecorder instance of the first request, then keep adding data to that instance for all the following requests rather than the new ISimplyRecorder instance for the following requests which you get in HomeController.
To solve it, you need to get ISimplyRecorder instance from the Invoke method of the middleware.
// using Microsoft.Extensions.DependencyInjection;
public async Task Invoke(HttpContext httpContext)
{
ISimplyRecorder recoder = httpContext.RequestServices.GetRequiredService<ISimplyRecorder>();
}
EDIT:
The comment of Juergen is correct, I tried it out. You may also just write like this:
public async Task Invoke(HttpContext httpContext, ISimplyRecorder recorder)
{
// recorder is from DI
}