Which is the best way to validate current password? - asp.net

I created a form where the user can update his data account. In this form the user is also able to change the account password, before doing so, I ask him the current password, this is the field:
<div class="form-group">
<label>Current Password</label>
<input class="form-control" id="oldPassword"
asp-for="#Model.ExistingPassword" type="password" />
<div class="invalid-feedback"></div>
</div>
as you can see the oldPassword input bound the property ExistingPassword which is part of the ViewModel of that View and have the following declaration:
[Required, MinLength(6), MaxLength(50), DataType(DataType.Password)]
public string ExistingPassword { get; set; }
when the form is submitted I call the following ajax function:
$.post(url, user, function (response) {
//Some stuff
}).done(function (response) {
alert("Updated executed");
}).fail(function (jqXHR, textStatus, errorThrown) {
alert("Error happened!");
});
the parameter of the function are taken by the form, in particular:
url: $(this).attr('action');
user: $(this).serialize();
the action of the form will call the following controller: User\UpdateUser.
Inside the UpdateUser method I execute the following check:
public async Task<UserProfileViewModel> UpdateUserAsync(UserProfileViewModel updatedUser)
{
if (!await _userManager.CheckPasswordAsync(originalUser, updatedUser.ExistingPassword))
throw new Exception("Invalid password");
essentially, the condition check if the current password is correct, if not, then an exception will raised.
Now, my question with this is: how can I know which type of exception the method has generated?
I need to know which type of exception the method UpdateUser has generated because there are different exceptions in the method.
Suppose the Invalid Password exceptions is raised, I need to display a message inside invalid-feedback div, next to oldPassword, so the user know why the update has failed.
Thanks in advance for any help.

Normally, I recommend not using an exception except in actual exception circumstances, but given the way you've designed this, you have a few options.
I'd suggest creating a custom "UpdateUserException" that you can throw that will include additional information, which can be provided by an enum or just string.
public class UpdateUserException : Exception {
public UpdateUserError ErrorCondition;
public UpdateUserException(UpdateUserError error, string message)
{
ErrorCondition = error;
Message = message;
}
}
then you would throw it
throw new UpdateUserException(UpdateUserError.BadPassword, "Invalid Password");
then you would catch it
try {}
catch (UpdateUserException e)
{
if (e.ErrorCondition == UpdateUserException.BadPassword)
{
// handle your exception.
}
}

Have a look at the UserManager ChangePassword Method.
You can bind the UserManager to use DependencyInjection like this (in Startup.cs)
public async void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
...
app.UseAuthentication();
app.UseMvc();
var scopeFactory = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>();
using (var scope = scopeFactory.CreateScope())
{
UserManager<User> userManager = scope.ServiceProvider.GetRequiredService<UserManager<User>>();
}
}
And then in your Controller s Constructor
private readonly UserManager<User> _userManager;
public AccountController(UserManager<User> userManager)
{
_userManager = userManager;
}
And finally your endpoint:
[HttpPost("ChangePassword")]
public async Task<IActionResult> ChangePassword([FromBody]ChangePasswordRequest changePasswordParams)
{
if (changePasswordParams == null)
return BadRequest($"{nameof(changePasswordParams)} must not be null!");
if (string.IsNullOrWhiteSpace(changePasswordParams.OldPassword) || string.IsNullOrWhiteSpace(changePasswordParams.NewPassword))
return BadRequest("old and new passwords have to be provided, but they both are empty.");
var userId = User.Claims.FirstOrDefault(c => c.Type == "id")?.Value;
var user = await _userManager.FindByIdAsync(userId);
var result = await _userManager.ChangePasswordAsync(user, changePasswordParams.OldPassword, changePasswordParams.NewPassword);
if (result.Succeeded)
return NoContent();
return BadRequest(result.Errors);
}
after that you can handle the errors in a switch statement.

Using Exceptions for handled errors are not recommended since they generally ends up with Internal Server error and actually It is beyond of its purpose.
The best approach would be to send BadRequest as It is stated by #maerlin.
However, If you insist to use Exceptions in your application or your applciation is architected to work in this way. I suggest you to inherit new CustomApplcationException class from ApplicationException and then inherit UpdateUserException and vs. from CustomApplicationException class. After that, I Suggest you to handle your exceptions in ErrorHandlingMiddleware and return HandledExceptions at least with BadRequest (400) status code.
The Example Code would be
public class ExceptionMiddleware
{
private readonly RequestDelegate _next;
private readonly ILoggerManager _logger;
public ExceptionMiddleware(RequestDelegate next, ILoggerManager logger)
{
_logger = logger;
_next = next;
}
public async Task InvokeAsync(HttpContext httpContext)
{
try
{
await _next(httpContext);
}
catch (CustomApplicationException cae)
{
await HandleCustomExceptionAsync(httpContext, cae);
}
catch (Exception ex)
{
_logger.LogError($"Something went wrong: {ex}");
await HandleExceptionAsync(httpContext, ex);
}
}
private static Task HandleExceptionAsync(HttpContext context, Exception exception)
{
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
return context.Response.WriteAsync(new ErrorDetails()
{
StatusCode = context.Response.StatusCode,
Message = "Internal Server Error from the custom middleware."
}.ToString());
}
private static Task HandleCustomExceptionAsync(HttpContext context, Exception exception)
{
context.Response.StatusCode = 400;
return context.Response.WriteAsync(new ErrorDetails()
{
StatusCode = context.Response.StatusCode,
Message = exception.Message
}.ToString());
}
}
then you need to regiter middleware in your Startup.cs
app.UseMiddleware<ExceptionMiddleware>();
please see https://code-maze.com/global-error-handling-aspnetcore/ and http://www.talkingdotnet.com/global-exception-handling-in-aspnet-core-webapi/ for further details.

Related

Different threads using same instance of DbContext, called from within DelegatingHandler

I have .Net Core 3.1 application that is using EF Core 3.1.9. During a specific process I am getting the following error:
A second operation started on this context before a previous operation completed. This is usually caused by different threads using the same instance of DbContext. For more information on how to avoid threading issues with DbContext, see https://go.microsoft.com/fwlink/?linkid=2097913
I am using Dependency Injection for the DbContext and have gone through all the flows to make sure everything is properly and immediately await'ed.
The error occurs within LtiUserRepository.cs which will be shown below.
That process starts with an external http call using an HttpClient that has a custom MessageHandler, registered in Startup.cs:
services.AddHttpClient<MyRepository>("MyCustomUserClient", client =>
{
var canvasUrl = Configuration.GetSection("Urls:Removed").Value ?? "https://example.com/";
client.BaseAddress = new System.Uri(removed);
}).AddHttpMessageHandler<LtiUserApiAuthenticationHttpClientHandler>();
The code that initiates the HTTP Call is:
public async Task<PlatformQuizSubmissions> GetUserQuiz(string courseId, string quizId)
{
var path = $"api/v1/courses/{courseId}/quizzes/{quizId}/submission";
var response = await _myCustomUserClient.GetAsync(path);
// some stuff
var responseContent = await response.Content.ReadAsStringAsync();
// Some other stuff
}
The purpose of the custom MessageHandler is to check for a header, get some data, and append a query parameter to each request
public sealed class LtiUserApiAuthenticationHttpClientHandler : DelegatingHandler
{
private readonly IHttpContextAccessor _accessor;
private readonly ILtiUserService _userService;
public LtiUserApiAuthenticationHttpClientHandler(IHttpContextAccessor accessor, ILtiUserService ltiUserService)
{
_accessor = accessor;
_userService = ltiUserService;
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var obo = _accessor.HttpContext.Request.Headers["QT-OBO"];
// THIS IS THE PART THAT QUERIES THE DATABASE
var user = await _userService.Get(new Guid(obo));
var uriBuilder = new UriBuilder(request.RequestUri);
if (string.IsNullOrEmpty(uriBuilder.Query))
{
uriBuilder.Query = $"as_user_id={user.PlatformUserId}";
}
else
{
uriBuilder.Query = $"{uriBuilder.Query}&as_user_id={user.PlatformUserId}";
}
request.RequestUri = uriBuilder.Uri;
return await base.SendAsync(request, cancellationToken);
}
}
You can see above that the MessageHandler calls _userservice.Get, which is this:
public async Task<LtiUser> Get(Guid guid)
{
return await _ltiUserRepository.Get(guid);
}
That simply returns from the repository, which is this:
public class LtiUserRepository : ILtiUserRepository
{
private readonly SqlDbContext _db;
private readonly IMapper _mapper;
private readonly ILogger<LtiUserRepository> _logger;
public LtiUserRepository(SqlDbContext sqlDbContext, IMapper mapper, ILoggerFactory logger)
{
_db = sqlDbContext;
_mapper = mapper;
_logger = logger != null ? logger.CreateLogger<LtiUserRepository>() : throw new ArgumentNullException(nameof(logger));
}
public async Task<LtiUser> Get(Guid guid)
{
try
{
return await _db.LtiUsers
.AsNoTracking()
.Where(l => l.UUID == guid)
.ProjectTo<LtiUser>(_mapper.ConfigurationProvider)
.SingleOrDefaultAsync();
}
catch (Exception ex)
{
// This is where the error is caught.
_logger.LogCritical($"Could not get LtiUser via (UUID) {guid} : {ex.Message}");
return null;
}
}
}
The database is registered in Startup.cs with:
protected virtual void ConfigureDatabaseServices(IServiceCollection services)
{
services.AddDbContext<SqlDbContext>(
o => o.UseSqlServer(Configuration.GetConnectionString("DbConnectionString")),
ServiceLifetime.Transient);
}
When I hit this endpoint using ApacheBench with 20 requests, concurrency of 2 I get this error anywhere from 2 to 10 times. However, looking at the following snippet from the MessageHandler (LtiUserApiAuthenticationHttpClientHandler) again:
var user = await _userService.Get(new Guid(obo));
if (string.IsNullOrEmpty(uriBuilder.Query))
{
uriBuilder.Query = $"as_user_id={user.PlatformUserId}";
}
else
{
uriBuilder.Query = $"{uriBuilder.Query}&as_user_id={user.PlatformUserId}";
}
If I replace user.PlatformUserId with a hardcoded, known value, (and comment out the call to _userService.Get) I can use AB with 1000 requests and a concurrency of 20 and have 0 occurrences of the issue. That leads me to believe I have it narrowed down to the offending flow, but am not sure of the correct way to do this.

Handling API validation errors in Blazor WebAssembly

I am learning Blazor, and I have a WebAssembly client application.
I created a WebAPI at the server which does some additional validation over and above the standard data annotation validations. For example, as it attempts to write a record to the database it checks that no other record exists with the same email address. Certain types of validation can't reliably happen at the client, particularly where race conditions could produce a bad result.
The API controller returns a ValidationProblem result to the client, and Postman shows the body of the result as:
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "|f06d4ffe-4aa836b5b3f4c9ae.",
"errors": {
"Email": [
"The email address already exists."
]
}
}
Note that the validation error is in the "errors" array in the JSON.
Back in the Blazor Client application, I have the typical HandleValidSubmit function that posts the data to the API and receives a response, as shown here:
private async void HandleValidSubmit()
{
var response = await Http.PostAsJsonAsync<TestModel>("api/Test", testModel);
if (response.StatusCode != System.Net.HttpStatusCode.Created)
{
// How to handle server-side validation errors?
}
}
My question is, how to best process server-side validation errors? The user experience ought to be the same as any other validation error, with the field highlighted, the validation message shown, and the summary at the top of the page.
I ended up solving this by creating a ServerValidator component. I'll post the code here in case it is helpful for others seeking a solution to the same problem.
This code assumes you are calling a Web API endpoint that returns a ValidationProblem result if there are issues.
public class ServerValidator : ComponentBase
{
[CascadingParameter]
EditContext CurrentEditContext { get; set; }
protected override void OnInitialized()
{
base.OnInitialized();
if (this.CurrentEditContext == null)
{
throw new InvalidOperationException($"{nameof(ServerValidator)} requires a cascading " +
$"parameter of type {nameof(EditContext)}. For example, you can use {nameof(ServerValidator)} " +
$"inside an EditForm.");
}
}
public async void Validate(HttpResponseMessage response, object model)
{
var messages = new ValidationMessageStore(this.CurrentEditContext);
if (response.StatusCode == HttpStatusCode.BadRequest)
{
var body = await response.Content.ReadAsStringAsync();
var validationProblemDetails = JsonSerializer.Deserialize<ValidationProblemDetails>(body);
if (validationProblemDetails.Errors != null)
{
messages.Clear();
foreach (var error in validationProblemDetails.Errors)
{
var fieldIdentifier = new FieldIdentifier(model, error.Key);
messages.Add(fieldIdentifier, error.Value);
}
}
}
CurrentEditContext.NotifyValidationStateChanged();
}
// This is to hold the response details when the controller returns a ValidationProblem result.
private class ValidationProblemDetails
{
[JsonPropertyName("status")]
public int? Status { get; set; }
[JsonPropertyName("title")]
public string Title { get; set; }
[JsonPropertyName("type")]
public string Type { get; set; }
[JsonPropertyName("errors")]
public IDictionary<string, string[]> Errors { get; set; }
}
}
To use this new component, you will need to add the component within your EditForm:
<EditForm Model="agency" OnValidSubmit="HandleValidSubmit">
<ServerValidator #ref="serverValidator" />
<ValidationSummary />
... put all your form fields here ...
</EditForm>
Lastly, you can kick off the validation in your #code section:
#code {
private TestModel testModel = new TestModel();
private ServerValidator serverValidator;
private async void HandleValidSubmit()
{
var response = await Http.PostAsJsonAsync<TestModel>("api/TestModels", testModel);
if (response.StatusCode != System.Net.HttpStatusCode.Created)
{
serverValidator.Validate(response, testModel);
}
else
{
Navigation.NavigateTo(response.Headers.Location.ToString());
}
}
}
In theory, this ought to allow you to bypass client validation entirely and rely on your Web API to do it. In practice, I found that Blazor performs client validation when there are annotations on your model, even if you don't include a <DataAnnotationsValidator /> in your form. However, it will still catch any validation issues at the server and return them to you.
how to best process server-side validation errors? The user experience ought to be the same as any other validation error, with the field highlighted, the validation message shown, and the summary at the top of the page.
I don't know what comes in your response, so I made a generic version of a component that do what you need.
Get the CascadingParameter of the EditContext
[CascadingParameter]
public EditContext EditContext { get; set; }
Have a ValidationMessageStore to hold the errors and a function that will display the errors
private ValidationMessageStore _messageStore;
private EventHandler<ValidationRequestedEventArgs> OnValidationRequested => (s, e) =>
{
_messageStore.Clear();
};
private EventHandler<FieldChangedEventArgs> OnFieldChanged => (s, e) =>
{
_messageStore.Clear(e.FieldIdentifier);
};
protected override void OnInitialized()
{
base.OnInitialized();
if (EditContext != null)
{
_messageStore = new ValidationMessageStore(EditContext);
EditContext.OnFieldChanged += OnFieldChanged;
EditContext.OnValidationRequested += OnValidationRequested;
}
}
public override void Dispose()
{
base.Dispose();
if (EditContext != null)
{
EditContext.OnFieldChanged -= OnFieldChanged;
EditContext.OnValidationRequested -= OnValidationRequested;
}
}
private void AddFieldError(ERROR_CLASS_YOU_ARE_USING validatorError)
{
_messageStore.Add(EditContext.Field(validatorError.FIELD_NAME), validatorError.ERROR_MESSAGE);
}
Call the function of the component using it's ref
private async void HandleValidSubmit()
{
var response = await Http.PostAsJsonAsync<TestModel>("api/Test", testModel);
if (response.StatusCode != System.Net.HttpStatusCode.Created)
{
// How to handle server-side validation errors?
// You could also have a foreach or a function that receives an List for multiple fields error display
MyHandleErrorComponent.AddFieldError(response.ERROR_PROPERTY);
}
}
https://learn.microsoft.com/en-us/aspnet/core/blazor/forms-validation has an example of how to handle server-side validation errors:
private async Task HandleValidSubmit(EditContext editContext)
{
customValidator.ClearErrors();
try
{
var response = await Http.PostAsJsonAsync<Starship>(
"StarshipValidation", (Starship)editContext.Model);
var errors = await response.Content
.ReadFromJsonAsync<Dictionary<string, List<string>>>();
if (response.StatusCode == HttpStatusCode.BadRequest &&
errors.Count() > 0)
{
customValidator.DisplayErrors(errors);
}
else if (!response.IsSuccessStatusCode)
{
throw new HttpRequestException(
$"Validation failed. Status Code: {response.StatusCode}");
}
else
{
disabled = true;
messageStyles = "color:green";
message = "The form has been processed.";
}
}
catch (AccessTokenNotAvailableException ex)
{
ex.Redirect();
}
catch (Exception ex)
{
Logger.LogError("Form processing error: {Message}", ex.Message);
disabled = true;
messageStyles = "color:red";
message = "There was an error processing the form.";
}
}
Use two phase validation.
Hook up an event for when the email is entered which calls an "IsEmailUnique" method on your api. This offers your user real time validation information. Perhaps disable the "Save" button until the email has been validated on the server.
You can then handle the Bad Request as you would any other server-side errors.

ASP.NET Core - getting a message back from AuthenticationHandler

I have implemented a subclass of AuthenticationHandler. It returns AuthenticationResult.Fail("This is why you can't log in");
I would have expected this message to end up in the body, or at least in the HTTP status text, but instead I get a blank 401 response.
Is there any way to provide additional information for failed authentication attempts in ASP.NET core?
Override HandleChallengeAsync:
In the example below the failReason is a private field in my implementation of AuthenticationHandler.
I don't know if this is the best way to pass the reason for failure. But the AuthenticationProperties on the AuthenticateResult.Fail method did not make it through to HandleChallengeAsync in my test.
public class CustomAuthenticationHandler<TOptions> : AuthenticationHandler<TOptions> where TOptions : AuthenticationSchemeOptions, new()
{
private string failReason;
public CustomAuthenticationHandler(IOptionsMonitor<TOptions> options
, ILoggerFactory logger
, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock) { }
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
failReason = "Reason for auth fail";
return AuthenticateResult.Fail(failReason);
}
protected override Task HandleChallengeAsync(AuthenticationProperties properties)
{
Response.StatusCode = 401;
if (failReason != null)
{
Response.HttpContext.Features.Get<IHttpResponseFeature>().ReasonPhrase = failReason;
}
return Task.CompletedTask;
}
}
From the docs: https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.authentication.authenticationhandler-1?view=aspnetcore-2.2
Override this method to deal with 401 challenge concerns, if an authentication scheme in question deals an authentication interaction as part of it's request flow. (like adding a response header, or changing the 401 result to 302 of a login page or external sign-in location.)
Source:
https://github.com/aspnet/Security/blob/master/src/Microsoft.AspNetCore.Authentication/AuthenticationHandler.cs#L201
I used this code in my custom Middleware to return problemDetails response.
public async Task Invoke(HttpContext httpContext)
{
await this.Next(httpContext);
if (httpContext.Response.StatusCode == StatusCodes.Status401Unauthorized)
{
var authenticateResult = await httpContext.AuthenticateAsync();
if (authenticateResult.Failure != null)
{
var routeData = httpContext.GetRouteData() ?? new RouteData();
var actionContext = new ActionContext(httpContext, routeData, new ActionDescriptor());
var problemDetails = this.ProblemDetailsFactory.CreateProblemDetails(httpContext,
statusCode: httpContext.Response.StatusCode,
detail: authenticateResult.Failure.Message);
var result = new ObjectResult(problemDetails)
{
ContentTypes = new MediaTypeCollection(),
StatusCode = problemDetails.Status,
DeclaredType = problemDetails.GetType()
};
await this.Executor.ExecuteAsync(actionContext, result);
}
}
}
For changing the body or Http status, you could try Context.Response.
Here is a demo code:
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
namespace TestIdentity
{
public class CustomAuthenticationHandler<TOptions> : AuthenticationHandler<TOptions> where TOptions : AuthenticationSchemeOptions, new()
{
public CustomAuthenticationHandler(IOptionsMonitor<TOptions> options
, ILoggerFactory logger
, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock)
{
}
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
await Context.Response.WriteAsync("This is why you can't log in");
return AuthenticateResult.Fail("This is why you can't log in");
}
}
}

Asp.net core 2 XUnit -- Unit Test MVC controller that throws exception

I am trying to unit test a controller that returns an IActionResult but can also throw an exception in certain circumstances. The problem I am running into is I'm not sure how to call it as the Assert throws an error where you cannot convert from IActionResult to Action.
How would I go about testing below statement?
Assert.Throws<Exception>(await controller.SendEmail(email)); //how to test this
I looked through the Microsoft testing controller documentation and didn't find something relevant. Most examples I see testing exceptions are for things like accessing repositories or services.
I understand I can return a badrequest or redirect to the page with an error message. But is what I am trying to accomplish possible?
My HomeController Method
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> SendEmail(EmailModel emailModel)
{
if(!ModelState.IsValid)
{
return View("Index",emailModel);
}
var response = await _sendEmail.SendEmailMessage(emailModel);
if (response != System.Net.HttpStatusCode.Accepted)
{
throw new Exception("Email failed to send, please try again later");
}
else
{
TempData["message"] = $"Email has been sent";
}
return RedirectToAction("Index");
}
XUnit HomeControllerTest Constructor for arrange
private Mock<ISendEmail> mockSendEmail;
private HomeController controller;
public HomeControllerShould()
{
mockSendEmail = new Mock<ISendEmail>();
mockSendEmail.Setup(x => x.SendEmailMessage(It.IsAny<EmailModel>())).ReturnsAsync(HttpStatusCode.Accepted);
controller = new HomeController(mockSendEmail.Object);
}
XUnit Test for Sending Email
[Fact]
public async Task SendEmailActionThrowsExceptionOnEmailFailure()
{
mockSendEmail.Setup(x => x.SendEmailMessage(It.IsAny<EmailModel>())).ReturnsAsync(HttpStatusCode.InternalServerError);
var email = new EmailModel();
Assert.Throws<Exception>(await controller.SendEmail(email)); //how to test this
}
Assert.Throws requires a function. You could use ThrowsAsync.
[Fact]
public async Task SendEmailActionThrowsExceptionOnEmailFailure()
{
mockSendEmail.Setup(x => x.SendEmailMessage(It.IsAny<EmailModel>()))
.ReturnsAsync(HttpStatusCode.InternalServerError);
var email = new EmailModel();
await Assert.ThrowsAsync<Exception>(() => controller.SendEmail(email));
}
FYI: We don't normally return HttpStatusCode from service layer such as email service, but I'll let you decide.

HttpContext.Current is null after Task.Run

Here are my project details
A web-API project containing webapi controllers
I have a separate c# Library project that contains models for my webapi and some method and api for intracting with database.
settings in webconfig
<httpRuntime targetFramework="4.5"/>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true"/>
Issue: HttpContext.Current.user is null.I want to access Httpcontext.Current.user in my c# library project.
1.In the code snippet below HttpContext.Current.user is available.This method exist in webapi project.
[HttpPost]
public async Task<IHttpActionResult> Post([FromBody]TEntity entity)
{
System.Security.Principal.IPrincipal p = System.Threading.Thread.CurrentPrincipal;
// context is available till here
var context =HttpContext.Current.User;
return await Task<IHttpActionResult>.Run(() =>
{
if (!ModelState.IsValid)
{
return (IHttpActionResult)Content(HttpStatusCode.BadRequest, ModelState.ToUnexpectedResultWrapper());
}
try
{
TOrchestrator orchestrator = new TOrchestrator();
orchestrator.Insert(entity);
}
catch (ValidationException ex)
{
return Content(HttpStatusCode.BadRequest, ex.ToUnexpectedResultWrapper());
}
catch (DbEntityValidationException ex)
{
return Content(HttpStatusCode.BadRequest, ex.ToUnexpectedResultWrapper());
}
return CreatedAtRoute("REST", new { id = entity.Id }, entity);
});
}
2.In code snippet below that exist in C# library. HttContext.Current.user is null. this method is called from the above method "Post".
public void Insert(Market market)
{
// Context is
System.Security.Principal.IPrincipal p = System.Threading.Thread.CurrentPrincipal;
//IOATIApplicationUser user = UserContextHelper.GetOATIContext().OATIUser;
var http = HttpContext.Current.User;
RunAction<InsertAction, Market>(market);
}
More over I could access user object from System.Threading.Thread.CurrentPrincipal.
If I cant access user object from HttpContext. Can i user System> System.Threading.Thread.CurrentPrincipal. I have heard it is not safe to user "System.Threading.Thread.CurrentPrincipal" and it is ment for window forms only.
HttpContext.Current returns the current HttpContext being serviced by the calling thread. When you start a background task by using Task.Run, it is not associated with an HTTP context by design.
Since you should not be using Task.Run on ASP.NET anyway, removing it is the easiest solution:
[HttpPost]
public IHttpActionResult Post([FromBody]TEntity entity)
{
if (!ModelState.IsValid)
{
return (IHttpActionResult)Content(HttpStatusCode.BadRequest, ModelState.ToUnexpectedResultWrapper());
}
try
{
TOrchestrator orchestrator = new TOrchestrator();
orchestrator.Insert(entity);
}
catch (ValidationException ex)
{
return Content(HttpStatusCode.BadRequest, ex.ToUnexpectedResultWrapper());
}
catch (DbEntityValidationException ex)
{
return Content(HttpStatusCode.BadRequest, ex.ToUnexpectedResultWrapper());
}
return CreatedAtRoute("REST", new { id = entity.Id }, entity);
}

Resources