What is the reason for this error? (.Net 5, C#) - c#

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}")]

Related

Entity Framework Core 6 - Cannot insert explicit value for identity column in table 'Roles' when IDENTITY_INSERT is set to OFF

I currently have a problem with EF6 and Fluent API. When inserting into database where model have one to many relationship, I'm getting this error. I've checked some related topics, but I want to keep autoincrement. Model without one to many relationship works perfectly.
Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
---> Microsoft.Data.SqlClient.SqlException (0x80131904): Cannot insert explicit value for identity column in table 'Roles' when IDENTITY_INSERT is set to OFF.
at Microsoft.Data.SqlClient.SqlCommand.<>c.<ExecuteDbDataReaderAsync>b__188_0(Task`1 result)
at System.Threading.Tasks.ContinuationResultTaskFromResultTask`2.InnerInvoke()
at System.Threading.Tasks.Task.<>c.<.cctor>b__272_0(Object obj)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location ---
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread)
--- End of stack trace from previous location ---
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
ClientConnectionId:501a6880-e298-43d5-be69-fcbebacdb15e
Error Number:544,State:1,Class:16
--- End of inner exception stack trace ---
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(StateManager stateManager, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at WorkIT_Backend.Services.UserService.Create(String username, String password, String role) in C:\Users\Ondřej\Desktop\škola\2022 PRF\WS\OPR3\WorkIT_Backend\WorkIT_Backend\WorkIT_Backend\Services\UserService.cs:line 54
at WorkIT_Backend.Controllers.UsersController.CreateUser(UserDto user) in C:\Users\Ondřej\Desktop\škola\2022 PRF\WS\OPR3\WorkIT_Backend\WorkIT_Backend\WorkIT_Backend\Controllers\UsersController.cs:line 57
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
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>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|20_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.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 Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
Model classes
public sealed class Role
{
public long RoleId { get; set; }
public string? Name { get; set; }
public ICollection<User> Users { get; set; }
public Role()
{
Users = new HashSet<User>();
}
}
public class User
{
public long UserId { get; set; }
public string? UserName { get; set; }
public string? PasswordHash { get; set; }
public long RoleId { get; set; }
public virtual Role Role { get; set; }
public User()
{
}
}
OnModelCreating in dbcontext
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Role>(entity =>
{
entity.HasKey(q => q.RoleId);
entity.Property(q => q.RoleId)
.ValueGeneratedOnAdd();
entity.Property(q => q.Name)
.IsRequired();
entity.HasIndex(q => q.Name)
.IsUnique();
});
modelBuilder.Entity<User>(entity =>
{
entity.HasKey(q => q.UserId);
entity.Property(q => q.UserId)
.ValueGeneratedOnAdd();
entity.Property(q => q.UserName)
.IsRequired();
entity.Property(q => q.PasswordHash)
.IsRequired();
entity.HasOne(u => u.Role)
.WithMany(r => r.Users)
.HasForeignKey(u => u.RoleId)
.OnDelete(DeleteBehavior.ClientSetNull);
});
}
Method in service which is adding the user
public async Task<User> Create(string username, string password, string role)
{
EnsureNotNull(username, nameof(username));
EnsureNotNull(password, nameof(password));
EnsureNotNull(role, nameof(role));
username = username.ToLower();
if (_context.Users.Any(q => q.UserName == username))
throw CreateException($"User {username} already exists.", null);
var hash = _securityService.HashPassword(password);
var userRole = await _roleService.GetRole(role);
var ret = new User {UserName = username, PasswordHash = hash, Role = userRole};
_context.Users.Add(ret);
await _context.SaveChangesAsync();
return ret;
}
This method for adding roles works perfectly
public class RoleService
{
private readonly WorkItDbContext _context;
private readonly SecurityService _securityService;
public RoleService(WorkItDbContext context, SecurityService securityService)
{
_context = context;
_securityService = securityService;
}
public async Task<Role> Create(string name)
{
EnsureNotNull(name, nameof(name));
name = name.ToLower();
if (_context.Roles.Any(q => q.Name == name))
throw CreateException($"Role {name} already exists.", null);
var ret = new Role {Name = name};
_context.Add(ret);
await _context.SaveChangesAsync();
return ret;
}
public async Task<List<Role>> GetRoles()
{
var roles = await _context.Roles.ToListAsync();
return roles;
}
public async Task<Role> GetRole(string name)
{
var role = await _context.Roles.FirstAsync(q => q.Name == name) ??
throw CreateException($"Role {name} does not exist.");
return role;
}
}
Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSingleton<IConfiguration>(builder.Configuration);
SecurityService securityService = new(builder.Configuration);
builder.Services.AddTransient<WorkItDbContext>();
builder.Services.AddSingleton<SecurityService>();
builder.Services.AddTransient<UserService>();
builder.Services.AddTransient<RoleService>();
I've different combination of dbcontext methods. I tried auto increment through anotation - identity. I've checked SQL server and autoincrement is alright.
Change
builder.Services.AddTransient<WorkItDbContext>();
to
builder.Services.AddDbContext<WorkItDbContext>();
and then your UserService and RoleService will share a WorkItDbContext, because it will be added as a Scoped service. See DbContext in dependency injection for ASP.NET Core

API ASP.NET 5 "POST" successfully, although with the error "No route matches the supplied values"

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);
}

How to solve StringComparison.OrdinalIgnoreCase and LINQ issue?

Here's the code:
controller:
//POST api/substances
[HttpPost]
[ServiceFilter(typeof(ValidateNameExistsAttribute<Substance>))]
public ActionResult<SubstanceReadDto> CreateSubstance([FromBody]SubstanceSaveDto dto)
{
var substanceModel = _mapper.Map<Substance>(dto);
_repository.CreateSubstance(substanceModel);
_repository.SaveChanges();
var substanceReadDto = _mapper.Map<SubstanceReadDto>(substanceModel);
return CreatedAtRoute(nameof(GetSubstanceById), new {substanceReadDto.Id}, substanceReadDto);
}
Filter
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Pharmacy.Data;
using Pharmacy.Models;
namespace Pharmacy.Filters
{
public class ValidateNameExistsAttribute<T> : IActionFilter where T : class, INameEntity
{
private readonly PharmacyContext _context;
public ValidateNameExistsAttribute(PharmacyContext context)
{
_context = context;
}
public void OnActionExecuted(ActionExecutedContext context)
{
}
public void OnActionExecuting(ActionExecutingContext context)
{
if (context.ActionArguments.ContainsKey("dto"))
{
var entity = new object();
var dto = context.ActionArguments["dto"] as INameDto;
if (dto == null)
{
context.Result = new BadRequestObjectResult("Invalid request body");
return;
}
if (context.ActionArguments.ContainsKey("id"))
{
var id = (int) context.ActionArguments["id"];
entity = _context.Set<T>().SingleOrDefault(it => String.Equals(it.Name, dto.Name, StringComparison.OrdinalIgnoreCase) && it.Id != id);
}
else
{
entity = _context.Set<T>().SingleOrDefault(it => String.Equals(it.Name, dto.Name, StringComparison.OrdinalIgnoreCase));
}
if (entity != null)
{
var problemDetails = new ProblemDetails
{
Title = "Duplicate resource",
Detail = $"A record with provided name {dto.Name} already exists",
Instance = context.HttpContext.Request.Path
};
context.Result = new ObjectResult(problemDetails)
{
StatusCode = 409
};
}
}
}
}
}
and here's the error message: What's wrong with code?
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.6.1",
"title": "The LINQ expression 'DbSet\r\n .Where(s => string.Equals(\r\n a: s.Name, \r\n b: __dto_Name_0, \r\n comparisonType: OrdinalIgnoreCase))' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync(). See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.",
"status": 500,
"detail": " at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.g__CheckTranslated|8_0(ShapedQueryExpression translated, <>c__DisplayClass8_0& )\r\n at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)\r\n at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)\r\n at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)\r\n at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)\r\n at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)\r\n at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)\r\n at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)\r\n at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)\r\n at Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutor[TResult](Expression query)\r\n at Microsoft.EntityFrameworkCore.Storage.Database.CompileQuery[TResult](Expression query, Boolean async)\r\n at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCore[TResult](IDatabase database, Expression query, IModel model, Boolean async)\r\n at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass9_01.<Execute>b__0()\r\n at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQueryCore[TFunc](Object cacheKey, Func1 compiler)\r\n at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func1 compiler)\r\n at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.Execute[TResult](Expression query)\r\n at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.Execute[TResult](Expression expression)\r\n at System.Linq.Queryable.SingleOrDefault[TSource](IQueryable1 source, Expression1 predicate)\r\n at Pharmacy.Filters.ValidateNameExistsAttribute1.OnActionExecuting(ActionExecutingContext context) in D:\.Pharmac Project\pharmac\Filters\ValidateNameExistsAttribute.cs:line 43\r\n at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)\r\n at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeNextActionFilterAsync()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)\r\n at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)\r\n at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)\r\n at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)\r\n at Microsoft.AspNetCore.Routing.EndpointMiddleware.g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)\r\n at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)\r\n at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)\r\n at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)\r\n at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)\r\n at Serilog.AspNetCore.RequestLoggingMiddleware.Invoke(HttpContext httpContext)\r\n at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task)",
"traceId": "|9542c43b-43548354a97cc054."
}

Threading issue when using IViewComponentHelper to convert ViewComponent to HTML string

I'm trying to use IViewComponentHelper in a multi threaded manner. But it's throwing :( (see full exception at bottom of post)
System.NullReferenceException: Object reference not set to an instance of an object.
at Microsoft.AspNetCore.Http.DefaultHttpContext.get_Items()
I have no idea why.
Here's my setup: (simplified for brevity)
Controller:
public async Task<IActionResult> Get()
{
var pdfStream = await _pdfService.GenerateAsync();
return File(pdfStream, "application/pdf");
}
PdfService:
public class PdfService
{
private readonly PdfSDK _pdfSDK;
public constructor(PdfSDK pdfSDK)
{
_pdfSDK = pdfSDK;
}
public async Task<Stream> GenerateAsync()
{
List<Task<PdfDocument>> tasks = await _context.Foos.Select(x => DoWorkAsync(x));
var pdfs = await Task.WhenAll(tasks);
var mergedPdf = _pdfSDK.MergePdfs(pdfs);
return mergedPdf.Stream;
}
private async Task<PdfDocument> DoWorkAsync(Foo foo)
{
var html = await _renderViewComponentService.RenderViewComponentAsStringAsync<MyViewComponent>(foo);
var document = await _pdfSDK.HtmlToDocumentAsync(html);
return document;
}
}
PdfSDK:
public class PdfSDK
{
public async Task<PdfDocument> HtmlToDocumentAsync(string html)
{
using var pdfEngine = new PdfEngine();
var pdf = await pdfEngine.HtmlAsPdfAsync(html);
return pdf;
}
public PdfDocument MergePdfs(params PdfDocument[] pdfs)
{
var pdf = PdfDocument.Merge(pdfs);
return pdf;
}
}
MyViewComponent:
public class MyViewComponent : ViewComponent
{
public IViewComponentResult Invoke(Foo args)
{
return View(args);
}
}
Default.cshtml
#model Foo
<h1>Hello from #Foo.Id<h1>
RenderViewComponentService:
public class RenderViewComponentService
{
private readonly IServiceProvider _serviceProvider;
private readonly ITempDataProvider _tempDataProvider;
private readonly IViewComponentHelper _viewComponentHelper;
public RenderViewComponentService(
IServiceProvider serviceProvider,
ITempDataProvider tempDataProvider,
IViewComponentHelper viewComponentHelper
)
{
_serviceProvider = serviceProvider;
_tempDataProvider = tempDataProvider;
_viewComponentHelper = viewComponentHelper;
}
public async Task<string> RenderViewComponentAsStringAsync<TViewComponent>(object args)
where TViewComponent : ViewComponent
{
var viewContext = GetFakeViewContext();
(_viewComponentHelper as IViewContextAware).Contextualize(viewContext);
// this appears to call InvokeAsync in TViewComponent, but it'll also call Invoke (synchronously) if it's implemented
// see https://learn.microsoft.com/en-us/aspnet/core/mvc/views/view-components?view=aspnetcore-3.1#perform-synchronous-work
var htmlContent = await _viewComponentHelper.InvokeAsync<TViewComponent>(args); // exception is thrown here!
using var stringWriter = new StringWriter();
htmlContent.WriteTo(stringWriter, HtmlEncoder.Default);
var html = stringWriter.ToString();
return html;
}
private ViewContext GetFakeViewContext(ActionContext actionContext = null, TextWriter writer = null)
{
actionContext ??= GetFakeActionContext();
var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary());
var tempData = new TempDataDictionary(actionContext.HttpContext, _tempDataProvider);
var viewContext = new ViewContext(
actionContext,
NullView.Instance,
viewData,
tempData,
writer ?? TextWriter.Null,
new HtmlHelperOptions());
return viewContext;
}
private ActionContext GetFakeActionContext()
{
var httpContext = new DefaultHttpContext
{
RequestServices = _serviceProvider,
};
var routeData = new RouteData();
var actionDescriptor = new ActionDescriptor();
return new ActionContext(httpContext, routeData, actionDescriptor);
}
private class NullView : IView
{
public static readonly NullView Instance = new NullView();
public string Path => string.Empty;
public Task RenderAsync(ViewContext context)
{
if (context == null) { throw new ArgumentNullException(nameof(context)); }
return Task.CompletedTask;
}
}
}
Exception:
fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
An unhandled exception has occurred while executing the request.
System.NullReferenceException: Object reference not set to an instance of an object.
at Microsoft.AspNetCore.Http.DefaultHttpContext.get_Items()
at Microsoft.AspNetCore.Mvc.Routing.UrlHelperFactory.GetUrlHelper(ActionContext context)
at Microsoft.AspNetCore.Mvc.Razor.RazorPageActivator.<>c__DisplayClass4_0.<.ctor>b__0(ViewContext context)
at Microsoft.Extensions.Internal.PropertyActivator`1.Activate(Object instance, TContext context)
at Microsoft.AspNetCore.Mvc.Razor.RazorPagePropertyActivator.Activate(Object page, ViewContext context)
at Microsoft.AspNetCore.Mvc.Razor.RazorPageActivator.Activate(IRazorPage page, ViewContext context)
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.ViewComponents.ViewViewComponentResult.ExecuteAsync(ViewComponentContext context)
at Microsoft.AspNetCore.Mvc.ViewComponents.DefaultViewComponentInvoker.InvokeAsync(ViewComponentContext context)
at Microsoft.AspNetCore.Mvc.ViewComponents.DefaultViewComponentHelper.InvokeCoreAsync(ViewComponentDescriptor descriptor, Object arguments)
at MyProject.Services.RenderViewComponentService.RenderViewComponentToStringAsync[TViewComponent](Object args) in MyProject\Services\RenderViewComponentService.cs:line ??
at MyProject.Services.PdfService.DoWorkAsync(Foo foo) in MyProject\Services\PdfService.cs:line ??
at MyProject.Services.PdfService.GenerateAsync() in MyProject\Services\PdfService.cs:line ??
at MyProject.Controllers.MyController.Get() in MyProject\Controllers\MyController.cs:line ??
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
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>g__Awaited|13_0(ControllerActionInvoker
invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
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>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.HeaderPropagation.HeaderPropagationMiddleware.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)
I think the problem is how I Contextualize the IViewComponentHelper. But I'm at a loss on how else to do it.
Can you spot anything I'm doing wrong?

Hash added into a POST http request

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;

Categories

Resources