I am trying to debug my code but I am getting System.NullReferenceException exception just after adding [frombody] to the parameter but when I removed [frombody] and tried again everything worked normaly
This my controller:
public async Task<IActionResult> Register([FromBody] UserForRegisterDTO userForRegisterDTO)
{
//validate request
userForRegisterDTO.Username = userForRegisterDTO.Username.ToLower();
if(await _repo.UserExist(userForRegisterDTO.Username))
return BadRequest("Username is already taken");
}
DTO :
namespace DatingApp.API.DTO
{
public class UserForRegisterDTO
{
public string Username { get; set; }
public string Password { get; set; }
}
}
Postman :
Error:
fail:
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware1
An unhandled exception has occurred while executing the request. System.NullReferenceException: Object reference not set to an instance
of an object.
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter()
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync()
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync()
at Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext)
at Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware.Invoke(HttpContext httpContext)
at Microsoft.AspNetCore.Cors.Infrastructure.CorsMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
Solved
Something strange happened. I solved this problem by using "dotnet watch run " instead of "dotnet run "
Related
Even though it looks like a duplicate question, none of the StackOverflow answers seem to fit or solve my problem.
Basically, I'm making a REST API using ASP.NET 5, with two entities: "Server" and "Video", the entity "Video" being dependent on the entity "Server".
The GET, POST, PUT, DELETE... methods are all working with the "Server" entity; the problem is when I try to use POST on the "Video" entity.
System.InvalidOperationException: No route matches the supplied values.
at Microsoft.AspNetCore.Mvc.CreatedAtActionResult.OnFormatting(ActionContext context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ObjectResultExecutor.ExecuteAsyncCore(ActionContext context, ObjectResult result, Type objectType, Object value)
at Microsoft.AspNetCore.Mvc.Infrastructure.ObjectResultExecutor.ExecuteAsync(ActionContext context, ObjectResult result)
at Microsoft.AspNetCore.Mvc.ObjectResult.ExecuteResultAsync(ActionContext context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultAsync(IActionResult result)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeNextResultFilterAsync[TFilter,TFilterAsync]()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
The funny part is that, even though it returns the error, the JSON is being posted successfully when I check with GET.
Here's a chunk of VideosController's code:
namespace SeventhApi.Controllers
{
[Route("api/servers/{serverId}/videos")]
[ApiController]
public class VideosController : ControllerBase
{
private readonly VideoContext _context;
public VideosController(VideoContext context)
{
_context = context;
}
[HttpGet("{id}")]
public async Task<ActionResult<Video>> GetVideo(Guid id)
{
var video = await _context.Videos.FindAsync(id);
if (video == null)
{
return NotFound();
}
return video;
}
[HttpPost]
public async Task<ActionResult<Video>> PostVideo(Video video)
{
_context.Videos.Add(video);
await _context.SaveChangesAsync();
return CreatedAtAction("GetVideo", new { id = video.VideoId }, video);
}
And a chunk o the Startup:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddDbContext<ServerContext>(opt => opt.UseInMemoryDatabase("Server"));
services.AddDbContext<VideoContext>(opt => opt.UseInMemoryDatabase("Video"));
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
From the answers I've found here, I'm inclined to think it's some routing error, but none of the answers have solved my problem.
url have two parameters, {serverId} {id}.
return CreatedAtAction("GetVideo", new { id = video.VideoId, serverId = 1 }, video);
As Hazrelle replied, it was really a matter of using nameof(GetVideo):
[HttpPost]
[ActionName(nameof(GetVideo))]
public async Task<ActionResult<Video>> PostVideo(Video video)
{
_context.Videos.Add(video);
await _context.SaveChangesAsync();
return CreatedAtAction(nameof(GetVideo), new { id = video.VideoId }, video);
}
I am coding a dynamic website, everything works but I noticed an error in the terminal.
Error:
fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
An unhandled exception has occurred while executing the request.
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: Cannot perform runtime binding on a null reference
at CallSite.Target(Closure , CallSite , Object )
at AspNetCore.Views_Content_CategoryContent.ExecuteAsync() in C:\Users\lenovo\Desktop\Projeler\Wutemp\Views\Content\CategoryContent.cshtml:line 2
at Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageCoreAsync(IRazorPage page, ViewContext context)
at Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageAsync(IRazorPage page, ViewContext context, Boolean invokeViewStarts)
at Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderAsync(ViewContext context)
at Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ViewContext viewContext, String contentType, Nullable`1 statusCode)
at Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ViewContext viewContext, String contentType, Nullable`1 statusCode)
at Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ActionContext actionContext, IView view, ViewDataDictionary viewData, ITempDataDictionary tempData, String contentType, Nullable`1 statusCode)
at Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor.ExecuteAsync(ActionContext context, ViewResult result)
at Microsoft.AspNetCore.Mvc.ViewResult.ExecuteResultAsync(ActionContext context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResultFilterAsync>g__Awaited|29_0[TFilter,TFilterAsync](ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
Controller (Edit: I accidentally deleted the ViewBag part):
[Route("Content/{url}/{id}")]
public IActionResult Index(int id)
{
var content = repoContents.TGet(id);
//If content has a category, go to CategoryContent
if(content.ContentCategory != null && content.ContentCategory != 0){
return RedirectToAction("CategoryContent", new
{
category = repoContentCategories.TGet((int)content.ContentCategory).Title,
url = content.URL,
id = content.ID
});
}
else{
ViewBag.Content = content;
return View();
}
}
What is the problem, and how can I solve it?
I solved the problem.
I used model instead of ViewBag mentioned in comments it didn't work I kept getting the same error
I think the problem is due to the similarity of the route parts of the 2 Views.
Index:
[Route("Content/{url}/{id}")]
public IActionResult Index(int id)
{
var content = repoContents.TGet(id);
//If content has a category, go to CategoryContent
if(content.ContentCategory != null && content.ContentCategory != 0){
return RedirectToAction("CategoryContent", new
{
category = repoContentCategories.TGet((int)content.ContentCategory).Title,
url = content.URL,
id = content.ID
});
}
else{
ViewBag.Content = content;
return View();
}
}
CategoryContent:
[Route("Content/{category}/{url}/{id}")]
public IActionResult CategoryContent(int id)
{
ViewBag.Content = repoContents.TGet(id);
return View();
}
I solved the problem by changing the Route part of the ContentCategory page
[Route("Content/{category}/{url}/{id}")]
|
V
[Route("Category-Content/{category}/{url}/{id}")]
I am following along with the Asp.net Core MVC tutorial here.
My project works when navigating to Students/Index but when I navigate to Students/Edit/1 I have the below error.
XmlException: '.', hexadecimal value 0x00, is an invalid character. Line 1, position 1.
System.Xml.XmlTextReaderImpl.Throw(Exception e)
CryptographicException: An error occurred while trying to encrypt the provided data. Refer to the inner exception for more information.
Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.Protect(byte[] plaintext)
I found a solution to this issue on another post on this website here.
While this solution does work for me I am wondering why this step is necessary? I know my question may be broad but how would I know by looking at the errors below to add the services.AddDataProtection to the configure services in Startup.cs? I would comment on the question where I found the solution but I do not have enough reputation.
Below is the full text of the errors.
XmlException: '.', hexadecimal value 0x00, is an invalid character. Line 1, position 1.
System.Xml.XmlTextReaderImpl.Throw(Exception e)
System.Xml.XmlTextReaderImpl.Throw(string res, string[] args)
System.Xml.XmlTextReaderImpl.ParseRootLevelWhitespace()
System.Xml.XmlTextReaderImpl.ParseDocumentContent()
System.Xml.XmlTextReaderImpl.Read()
System.Xml.XmlReader.MoveToContent()
System.Xml.Linq.XElement.Load(XmlReader reader, LoadOptions options)
System.Xml.Linq.XElement.Load(Stream stream, LoadOptions options)
System.Xml.Linq.XElement.Load(Stream stream)
Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository.ReadElementFromFile(string fullPath)
Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository.GetAllElementsCore()+MoveNext()
System.Collections.Generic.List<T>..ctor(IEnumerable<T> collection)
System.Linq.Enumerable.ToList<TSource>(IEnumerable<TSource> source)
Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository.GetAllElements()
Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager.GetAllKeys()
Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider.CreateCacheableKeyRingCore(DateTimeOffset now, IKey keyJustAdded)
Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider.Microsoft.AspNetCore.DataProtection.KeyManagement.Internal.ICacheableKeyRingProvider.GetCacheableKeyRing(DateTimeOffset now)
Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider.GetCurrentKeyRingCore(DateTime utcNow, bool forceRefresh)
Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider.GetCurrentKeyRing()
Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.Protect(byte[] plaintext)
CryptographicException: An error occurred while trying to encrypt the provided data. Refer to the inner exception for more information.
Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.Protect(byte[] plaintext)
Microsoft.AspNetCore.Antiforgery.DefaultAntiforgeryTokenSerializer.Serialize(AntiforgeryToken token)
Microsoft.AspNetCore.Antiforgery.DefaultAntiforgery.Serialize(IAntiforgeryFeature antiforgeryFeature)
Microsoft.AspNetCore.Antiforgery.DefaultAntiforgery.GetAndStoreTokens(HttpContext httpContext)
Microsoft.AspNetCore.Mvc.ViewFeatures.AntiforgeryExtensions.GetHtml(IAntiforgery antiforgery, HttpContext httpContext)
Microsoft.AspNetCore.Mvc.ViewFeatures.DefaultHtmlGenerator.GenerateAntiforgery(ViewContext viewContext)
Microsoft.AspNetCore.Mvc.TagHelpers.FormTagHelper.Process(TagHelperContext context, TagHelperOutput output)
Microsoft.AspNetCore.Razor.TagHelpers.TagHelper.ProcessAsync(TagHelperContext context, TagHelperOutput output)
Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperRunner.RunAsync(TagHelperExecutionContext executionContext)
AspNetCore.Views_Students_Edit.ExecuteAsync()
Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageCoreAsync(IRazorPage page, ViewContext context)
Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageAsync(IRazorPage page, ViewContext context, bool invokeViewStarts)
Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderAsync(ViewContext context)
Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ViewContext viewContext, string contentType, Nullable<int> statusCode)
Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ViewContext viewContext, string contentType, Nullable<int> statusCode)
Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ActionContext actionContext, IView view, ViewDataDictionary viewData, ITempDataDictionary tempData, string contentType, Nullable<int> statusCode)
Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor.ExecuteAsync(ActionContext context, ViewResult result)
Microsoft.AspNetCore.Mvc.ViewResult.ExecuteResultAsync(ActionContext context)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeResultAsync>g__Logged|21_0(ResourceInvoker invoker, IActionResult result)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResultFilterAsync>g__Awaited|29_0<TFilter, TFilterAsync>(ResourceInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed context)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext<TFilter, TFilterAsync>(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters()
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
Additional code:
controller for edit
// GET: Students/Edit/5
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var student = await _context.Students.FindAsync(id);
if (student == null)
{
return NotFound();
}
return View(student);
}
Startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<SchoolContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("ContosoConnectionString")));
services.AddDatabaseDeveloperPageExceptionFilter();
services.AddDataProtection().PersistKeysToFileSystem(new DirectoryInfo(#"c:\temp-keys\"));
services.AddControllersWithViews();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}
Student model
public class Student
{
public int ID { get; set; }
public string LastName { get; set; }
public string FirstMidName { get; set; }
public DateTime EnrollmentDate { get; set; }
public ICollection<Enrollment> Enrollments { get; set; }
}
SchoolContext
public class SchoolContext : DbContext
{
public SchoolContext(DbContextOptions<SchoolContext> options) : base(options)
{
}
public DbSet<Course> Courses { get; set; }
public DbSet<Enrollment> Enrollments { get; set; }
public DbSet<Student> Students { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Course>().ToTable("Course");
modelBuilder.Entity<Enrollment>().ToTable("Enrollment");
modelBuilder.Entity<Student>().ToTable("Student");
}
}
Thanks
I'm trying to integrate a hash into my database, which is generated by a POST request when creating a new user.
The APIs being new to me, I don't really understand the error and why my code failed. Is someone can explain to me what I am doing wrong and how I could make this work ?
Here's the code I wrote :
Controller
//POST: api/user/
[HttpPost]
public ActionResult<User> PostUserItem(User user)
{
string Hash = RandomNumberGenerator.GetInt32(1000, 9999).ToString();
SHA512 sha512 = SHA512.Create(Hash);
string Hashed = sha512.ToString();
user.Token_Validation = Hashed;
_context.UserItems.Add(user);
_context.SaveChanges();
return CreatedAtAction("GetUserItem", new User{idUser=user.idUser}, user);
}
Model
[Table("USERS")]
public class User
{
[Key]
public int idUser { get; set; }
public string name { get; set; }
public string lastName { get; set; }
public string email { get; set; }
public string pwd { get; set; }
public string Token_Validation { get; set; }
}
DBContext
public class RouteContext : DbContext
{
public RouteContext(DbContextOptions<RouteContext> options) : base(options)
{
}
public DbSet<User> UserItems { get; set; }
}
And here's the ERROR 500 I got when trying to use my API
System.NullReferenceException: Object reference not set to an instance of an object.
at LocalBeers.Controllers.UserController.PostUserItem(User user) in /var/www/html/backend/Controllers/UserController.cs:line 46
at lambda_method(Closure , Object , Object[] )
at Microsoft.Extensions.Internal.ObjectMethodExecutor.Execute(Object target, Object[] parameters)
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.SyncObjectResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeActionMethodAsync()
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeNextActionFilterAsync()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
This is incorrect:
string Hash = RandomNumberGenerator.GetInt32(1000, 9999).ToString();
SHA512 sha512 = SHA512.Create(Hash);
...At this point, sha512 is null and the next line throws NullReferenceException which causes the server to return an HTTP 500 (Internal Server Error) status.
The SHA512.Create(String) overload expects the name of an implementation, not the data you want to hash.
More information here.
Instead, try something like this:
var random = RandomNumberGenerator.GetInt32(1000, 9999).ToString();
string hashed = string.Empty;
using (SHA512 sha512 = SHA512.Create())
{
var hashValue = sha512.ComputeHash(System.Text.Encoding.Default.GetBytes(random));
hashed = System.Convert.ToBase64String(hashValue);
}
user.Token_Validation = hashed;
Using .NET Core 1.1, I've created an AuthorizationHandler:
public class HasStoreAccountAuthorizationHandler : AuthorizationHandler<HasStoreAccountRequirement>
{
private SessionHelper SessionHelper { get; }
public HasStoreAccountAuthorizationHandler(SessionHelper sessionHelper)
{
this.SessionHelper = sessionHelper;
}
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, HasStoreAccountRequirement requirement)
{
if (this.SessionHelper?.Accounts != null && this.SessionHelper.Accounts.Any()) context.Succeed(requirement);
return Task.FromResult(0);
}
}
And I have a SessionHelper class which serializes non-primitive values into session:
public class SessionHelper
{
public IEnumerable<AccountInformation> Accounts
{
get => this.Session.Get<IEnumerable<AccountInformation>>(AccountsKey);
set => this.Session.Set<IEnumerable<AccountInformation>>(AccountsKey, value);
}
public static class SessionHelperExtensionMethods
{
public static void Set<T>(this ISession session, string key, T value)
{
session.SetString(key, JsonConvert.SerializeObject(value));
}
public static T Get<T>(this ISession session, string key)
{
var value = session.GetString(key);
return value == null ? default(T) : JsonConvert.DeserializeObject<T>(value);
}
}
}
Accessing SessionHelper.Accounts anywhere else in the code works fine. However, whenever the policy AuthorizationHandler is called, the following error is thrown:
An exception was thrown while deserializing the token.
System.InvalidOperationException: The antiforgery token could not be decrypted.
---> System.Security.Cryptography.CryptographicException: The key {KEYNAME} was not found in the key ring.
at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.UnprotectCore(Byte[] protectedData, Boolean allowOperationsOnRevokedKeys, UnprotectStatus& status) at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.DangerousUnprotect(Byte[] protectedData, Boolean ignoreRevocationErrors, Boolean& requiresMigration, Boolean& wasRevoked) at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.Unprotect(Byte[] protectedData) at Microsoft.AspNetCore.Antiforgery.Internal.DefaultAntiforgeryTokenSerializer.Deserialize(String serializedToken) --- End of inner exception stack trace --- at Microsoft.AspNetCore.Antiforgery.Internal.DefaultAntiforgeryTokenSerializer.Deserialize(String serializedToken) at Microsoft.AspNetCore.Antiforgery.Internal.DefaultAntiforgery.GetCookieTokenDoesNotThrow(HttpContext httpContext) System.Security.Cryptography.CryptographicException: The key {KEYNAME} was not found in the key ring.
at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.UnprotectCore(Byte[] protectedData, Boolean allowOperationsOnRevokedKeys, UnprotectStatus& status) at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.DangerousUnprotect(Byte[] protectedData, Boolean ignoreRevocationErrors, Boolean& requiresMigration, Boolean& wasRevoked) at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.Unprotect(Byte[] protectedData) at Microsoft.AspNetCore.Antiforgery.Internal.DefaultAntiforgeryTokenSerializer.Deserialize(String serializedToken)
The web site machine key is set in the web.config and IIS,using SHA1/AES with both "Generate a unique key for each application" checked and unchecked (e.g., "KEY_VALUE,IsolateApps" and "KEY_VALUE").
I've also created a data protection registry hive and configured the IIS app pool to load the user profile per this link.
I've also added data protection in Startup.cs (with various lines added/removed):
services.AddAntiforgery();
services.AddDataProtection()
.SetApplicationName("APPNAME")
.SetDefaultKeyLifetime(TimeSpan.FromDays(365))
.PersistKeysToFileSystem(new DirectoryInfo(Configuration["DataProtection:LocalPaths:KeyLocation"]));
In some cases, SessionHelper.Accounts is read correctly and no exception is thrown. However, once the app recycles, eventually SessionHelper.Accounts is null and the exception is thrown. Logging out of the system and logging in again has no effect on error.
Thoughts?
I've managed to fix this by accessing the session data via the passed AuthorizationHandlerContext context instead of the IHttpContextAccessor context.
In SessionHelper:
public static IEnumerable<AccountInformation> GetAccounts(HttpContext context)
{
return context.Session.Get<IEnumerable<AccountInformation>>(AccountsKey);
}
In the AuthorizationHandler:
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, HasStoreAccountRequirement requirement)
{
var accounts = SessionHelper.GetAccounts(this.Context.HttpContext);
if (accounts != null && accounts.Any()) context.Succeed(requirement);
return Task.FromResult(0);
}