I am new to blazor, and ef core.
I need a parameter passed into a function on my DbContext, I have created a service that has an 'int' field, but I am struggling to inject this into the context... I'm not sure what I need to do here, everything I've tried still results in an error. Some help would be great...
I'm trying to inject the "_cookieRepo" into the code, but I cannot pass an additional parameter into the constructor, when i do i get the "Cannot resolve scoped services" error.
Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddServerSideBlazor();
services.AddDbContextFactory<OlqtContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))
.LogTo(log => Debug.WriteLine(log),
new[] { DbLoggerCategory.Database.Command.Name },
Microsoft.Extensions.Logging.LogLevel.Information)
.EnableSensitiveDataLogging());
services.AddScoped<ICookieRepository, CookieRepository.CookieRepository>();
}
DbContext:
public partial class OlqtContext : DbContext
{
private readonly ICookieRepository _cookieRepository;
public OlqtContext(DbContextOptions<OlqtContext> options, ICookieRepository cookieRepository)
: base(options)
{
ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
_cookieRepository = cookieRepository;
}
}
public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
{
var loginId = _cookieRepository.LoginId;
var dateTimeNow = DateTime.Now;
ChangeTracker.DetectChanges();
var modified = ChangeTracker.Entries().Where(x => x.State == EntityState.Added || x.State == EntityState.Modified || x.State == EntityState.Deleted);
foreach (var item in modified)
{
if (item.Entity is IAuditable entity)
{
if (item.State == EntityState.Added)
{
item.CurrentValues[nameof(IAuditable.CreatedByUserId)] = loginId;
item.CurrentValues[nameof(IAuditable.CreatedDate)] = dateTimeNow;
}
item.CurrentValues[nameof(IAuditable.LastModifiedByUserId)] = loginId;
item.CurrentValues[nameof(IAuditable.LastModifiedDate)] = dateTimeNow;
}
}
return base.SaveChangesAsync(cancellationToken);
}
Interface/Repo:
*Interface**
using System;
using System.Collections.Generic;
using System.Text;
namespace Olqt.CookieRepository
{
public interface ICookieRepository
{
public int LoginId { get; set; }
}
}
**Repo:**
using System;
using System.Collections.Generic;
using System.Text;
namespace Olqt.CookieRepository
{
public class CookieRepository : ICookieRepository
{
public int LoginId { get; set; }
}
}
The login ID is set here, in the loginrepo I created.
public partial class LoginRepository : GenericRepository<Login, LoginDto>, ILoginRepository
{
private readonly ICookieRepository _cookieRepository;
public LoginRepository(IDbContextFactory<OlqtContext> dbFactory, IMapper mapper, ICookieRepository cookieRepository) : base(dbFactory, mapper, cookieRepository)
{
_cookieRepository = cookieRepository;
}
public async Task<LoginDto> VerifyLoginAsync(string username, string password)
{
using var _context = GetOlqtContext();
LoginDto retval = null;
var login = await _context.Logins.Where(x => x.UserName == username && x.Password == password).FirstOrDefaultAsync();
if (login != null)
{
var ReturnLogin = new LoginDto
{
UserName = login.UserName,
Password = login.Password,
CreatedByUserId = login.LoginId
};
retval = ReturnLogin;
_cookieRepository.LoginId = login.LoginId;
}
return retval;
}
}
This is the error i receive:
An unhandled exception occurred while processing the request.
InvalidOperationException: Cannot resolve scoped service 'Olqt.CookieRepository.ICookieRepository' from root provider.
Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteValidator.ValidateResolution(Type serviceType, IServiceScope scope, IServiceScope rootScope)
InvalidOperationException: Cannot resolve scoped service 'Olqt.CookieRepository.ICookieRepository' from root provider.
Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteValidator.ValidateResolution(Type serviceType, IServiceScope scope, IServiceScope rootScope)
Microsoft.Extensions.DependencyInjection.ServiceProvider.Microsoft.Extensions.DependencyInjection.ServiceLookup.IServiceProviderEngineCallback.OnResolve(Type serviceType, IServiceScope scope)
Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, bool isDefaultParameterRequired)
lambda_method63(Closure , IServiceProvider , object[] )
Microsoft.EntityFrameworkCore.Internal.DbContextFactorySource<TContext>+<>c__DisplayClass4_0.<CreateActivator>b__1(IServiceProvider p, DbContextOptions<TContext> _)
Microsoft.EntityFrameworkCore.Internal.DbContextFactory<TContext>.CreateDbContext()
Olqt.Repository.Services.GenericRepository<T, T1>.GetOlqtContext() in GenericRepository.cs
return _dbFactory.CreateDbContext();
Olqt.Repository.Services.GenericRepository<T, T1>.GetAllAsync() in GenericRepository.cs
using var _context = GetOlqtContext();
Olqt.Server.Pages.Quote.Quote.OnInitializedAsync() in Quote.cs
Quotes = (await QuoteRepository.GetAllAsync())
Microsoft.AspNetCore.Components.ComponentBase.RunInitAndSetParametersAsync()
Microsoft.AspNetCore.Components.Rendering.HtmlRenderer.HandleException(Exception exception)
Microsoft.AspNetCore.Components.RenderTree.Renderer.AddToPendingTasks(Task task)
Microsoft.AspNetCore.Components.Rendering.ComponentState.SetDirectParameters(ParameterView parameters)
Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InitializeNewComponentFrame(ref DiffContext diffContext, int frameIndex)
Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InitializeNewSubtree(ref DiffContext diffContext, int frameIndex)
Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InsertNewFrame(ref DiffContext diffContext, int newFrameIndex)
Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InsertNewFrame(ref DiffContext diffContext, int newFrameIndex)
Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InsertNewFrame(ref DiffContext diffContext, int newFrameIndex)
Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.AppendDiffEntriesForRange(ref DiffContext diffContext, int oldStartIndex, int oldEndIndexExcl, int newStartIndex, int newEndIndexExcl)
Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.ComputeDiff(Renderer renderer, RenderBatchBuilder batchBuilder, int componentId, ArrayRange<RenderTreeFrame> oldTree, ArrayRange<RenderTreeFrame> newTree)
Microsoft.AspNetCore.Components.Rendering.ComponentState.RenderIntoBatch(RenderBatchBuilder batchBuilder, RenderFragment renderFragment)
Microsoft.AspNetCore.Components.RenderTree.Renderer.RenderInExistingBatch(RenderQueueEntry renderQueueEntry)
Microsoft.AspNetCore.Components.RenderTree.Renderer.ProcessRenderQueue()
Microsoft.AspNetCore.Components.Rendering.HtmlRenderer.HandleException(Exception exception)
Microsoft.AspNetCore.Components.RenderTree.Renderer.ProcessRenderQueue()
Microsoft.AspNetCore.Components.RenderTree.Renderer.ProcessPendingRender()
Microsoft.AspNetCore.Components.RenderTree.Renderer.AddToRenderQueue(int componentId, RenderFragment renderFragment)
Microsoft.AspNetCore.Components.ComponentBase.StateHasChanged()
Microsoft.AspNetCore.Components.ComponentBase.CallOnParametersSetAsync()
Microsoft.AspNetCore.Components.ComponentBase.RunInitAndSetParametersAsync()
Microsoft.AspNetCore.Components.Rendering.HtmlRenderer.HandleException(Exception exception)
Microsoft.AspNetCore.Components.RenderTree.Renderer.AddToPendingTasks(Task task)
Microsoft.AspNetCore.Components.Rendering.ComponentState.SetDirectParameters(ParameterView parameters)
Microsoft.AspNetCore.Components.RenderTree.Renderer.RenderRootComponentAsync(int componentId, ParameterView initialParameters)
Microsoft.AspNetCore.Components.Rendering.HtmlRenderer.CreateInitialRenderAsync(Type componentType, ParameterView initialParameters)
Microsoft.AspNetCore.Components.Rendering.HtmlRenderer.RenderComponentAsync(Type componentType, ParameterView initialParameters)
Microsoft.AspNetCore.Components.Rendering.RendererSynchronizationContext+<>c__11<TResult>+<<InvokeAsync>b__11_0>d.MoveNext()
Microsoft.AspNetCore.Mvc.ViewFeatures.StaticComponentRenderer.PrerenderComponentAsync(ParameterView parameters, HttpContext httpContext, Type componentType)
Microsoft.AspNetCore.Mvc.ViewFeatures.ComponentRenderer.PrerenderedServerComponentAsync(HttpContext context, ServerComponentInvocationSequence invocationId, Type type, ParameterView parametersCollection)
Microsoft.AspNetCore.Mvc.ViewFeatures.ComponentRenderer.RenderComponentAsync(ViewContext viewContext, Type componentType, RenderMode renderMode, object parameters)
Microsoft.AspNetCore.Mvc.TagHelpers.ComponentTagHelper.ProcessAsync(TagHelperContext context, TagHelperOutput output)
Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperRunner.<RunAsync>g__Awaited|0_0(Task task, TagHelperExecutionContext executionContext, int i, int count)
Olqt.Server.Pages.Pages__Host.<ExecuteAsync>b__35_1() in _Host.cshtml
<component type="typeof(App)" render-mode="ServerPrerendered" param-InitialState="initialTokenState" />
Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperExecutionContext.SetOutputContentAsync()
Olqt.Server.Pages.Pages__Host.ExecuteAsync() in _Host.cshtml
Layout = null;
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.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()
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
Related
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
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."
}
I have my model:
public class Membership
{
[Key]
[Required]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
[MinLength(3)]
[MaxLength(30)]
public string Name { get; set; }
[Required] public int PeriodType { get; set; }
[Required] public int Duration { get; set; }
[Required] public int TerminationPeriod { get; set; }
[Required] public float InstallmentPrice { get; set; }
}
And my Dto:
public class MembershipDto
{
public int Id { get; private set; }
public string Name { get; set; }
public int PeriodType { get; set; }
public int Duration { get; set; }
public int TerminationPeriod { get; set; }
public float InstallmentPrice { get; set; }
}
I'm using Entity Framework and JsonPatchDocument to make PATCH operation in my API, the code is following:
public async Task<MembershipDto> Handle(EditMembershipCommand request, CancellationToken cancellationToken)
{
var membershipEntity = await _dbContext
.Memberships
.SingleOrDefaultAsync(m => m.Id == request.Id);
if (membershipEntity is null)
throw new NullReferenceException($"Membership [Id: {request.Id}] not found");
var editedMembership = request.NewMembershipDto.Adapt<JsonPatchDocument<Membership>>(); //request.NewMembershipDto is type of JsonPatchDocument<MembershipDto>
editedMembership.ApplyTo(membershipEntity, ModelState);
_ = await _dbContext.SaveChangesAsync();
var membershipDto = editedMembership.Adapt<MembershipDto>();
return membershipDto;
}
As an output I get the following information:
ProblemDetails.ProblemDetailsMiddleware[1]
An unhandled exception has occurred while executing the request.
Mapster.CompileException: Error while compiling
source=Microsoft.AspNetCore.JsonPatch.JsonPatchDocument`1[AgreementApi.Dtos.MembershipDto]
destination=Microsoft.AspNetCore.JsonPatch.JsonPatchDocument`1[AgreementApi.Models.Membership]
type=Map
---> Mapster.CompileException: Error while compiling
source=Newtonsoft.Json.Serialization.IContractResolver
destination=Newtonsoft.Json.Serialization.IContractResolver
type=Map
---> System.InvalidOperationException: No default constructor for type 'IContractResolver', please use 'ConstructUsing' or 'MapWith'
at Mapster.Utils.DynamicTypeGenerator.CreateTypeForInterface(Type interfaceType)
at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
at Mapster.Utils.DynamicTypeGenerator.GetTypeForInterface(Type interfaceType)
at Mapster.Adapters.RecordTypeAdapter.CreateInstantiationExpression(Expression source, Expression destination, CompileArgument arg)
at Mapster.Adapters.BaseAdapter.CreateInstantiationExpression(Expression source, CompileArgument arg)
at Mapster.Adapters.RecordTypeAdapter.CreateInlineExpression(Expression source, CompileArgument arg)
at Mapster.Adapters.BaseAdapter.CreateInlineExpressionBody(Expression source, CompileArgument arg)
at Mapster.Adapters.BaseAdapter.CreateExpressionBody(Expression source, Expression destination, CompileArgument arg)
at Mapster.Adapters.BaseAdapter.CreateAdaptFunc(CompileArgument arg)
at Mapster.TypeAdapterConfig.CreateMapExpression(CompileArgument arg)
--- End of inner exception stack trace ---
at Mapster.TypeAdapterConfig.CreateMapExpression(CompileArgument arg)
at Mapster.TypeAdapterConfig.CreateInlineMapExpression(Type sourceType, Type destinationType, MapType mapType, CompileContext context, MemberMapping mapping)
at Mapster.Adapters.BaseAdapter.CreateAdaptExpressionCore(Expression source, Type destinationType, CompileArgument arg, MemberMapping mapping, Expression destination)
at Mapster.Adapters.BaseAdapter.CreateAdaptExpression(Expression source, Type destinationType, CompileArgument arg, MemberMapping mapping, Expression destination)
at Mapster.Adapters.ClassAdapter.CreateInlineExpression(Expression source, CompileArgument arg)
at Mapster.Adapters.BaseAdapter.CreateInlineExpressionBody(Expression source, CompileArgument arg)
at Mapster.Adapters.BaseAdapter.CreateExpressionBody(Expression source, Expression destination, CompileArgument arg)
at Mapster.Adapters.BaseAdapter.CreateAdaptFunc(CompileArgument arg)
at Mapster.TypeAdapterConfig.CreateMapExpression(CompileArgument arg)
--- End of inner exception stack trace ---
at Mapster.TypeAdapterConfig.CreateMapExpression(CompileArgument arg)
at Mapster.TypeAdapterConfig.CreateMapExpression(TypeTuple tuple, MapType mapType)
at Mapster.TypeAdapterConfig.CreateDynamicMapExpression(TypeTuple tuple)
at Mapster.TypeAdapterConfig.<GetDynamicMapFunction>b__66_0[TDestination](TypeTuple tuple)
at Mapster.TypeAdapterConfig.<>c__DisplayClass55_0`1.<AddToHash>b__0(TypeTuple types)
at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
at Mapster.TypeAdapterConfig.AddToHash[T](ConcurrentDictionary`2 hash, TypeTuple key, Func`2 func)
at Mapster.TypeAdapterConfig.GetDynamicMapFunction[TDestination](Type sourceType)
at Mapster.TypeAdapter.Adapt[TDestination](Object source, TypeAdapterConfig config)
at Mapster.TypeAdapter.Adapt[TDestination](Object source)
at Fitverse.AgreementApi.Handlers.EditMembershipHandler.Handle(EditMembershipCommand request, CancellationToken cancellationToken) in /Users/wonsu/Repositories/Fitverse/Fitverse.AgreementApi/Handlers/EditMembershipHandler.cs:line 34
at MediatR.Pipeline.RequestExceptionProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next)
at MediatR.Pipeline.RequestExceptionProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next)
at MediatR.Pipeline.RequestExceptionActionProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next)
at MediatR.Pipeline.RequestExceptionActionProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next)
at MediatR.Pipeline.RequestPostProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next)
at MediatR.Pipeline.RequestPreProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next)
at Fitverse.AgreementApi.Controllers.SettingsController.EditMembership(Int32 id, JsonPatchDocument`1 membershipDto) in /Users/wonsu/Repositories/Fitverse/Fitverse.AgreementApi/Controllers/SettingsController.cs:line 52
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|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 Hellang.Middleware.ProblemDetails.ProblemDetailsMiddleware.Invoke(HttpContext context)
I know that the issue is in this line of code:
var editedMembership = request.NewMembershipDto.Adapt<JsonPatchDocument<Membership>>();
But I don't know how to change it to properly map it to desired type. Could you help me? :)
I know that at the end I should probably get the membership from DB again, map it and return it instead of just mapping editedMembership, but I'll fit it after dealing with this mapping issue.
Add the mapping of IContractResolver helps resolve the issue.
private static TypeAdapterConfig GetConfiguredMappingConfig()
{
var config = TypeAdapterConfig.GlobalSettings;
IList<IRegister> registers = config.Scan(Assembly.GetExecutingAssembly());
config.Apply(registers);
config.NewConfig<IContractResolver, IContractResolver>()
.ConstructUsing(src => new DefaultContractResolver());
return config;
}
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?
Blazor - .NET Core 3 Preview 6
I'm trying to build component that takes a property as lambda-expression in and then present info about that property for the user.
I seem to be able to get all the data if I declare the object and bind it as an expression on the component directly. But if I first pass the object as a parameter to a component and then, as nested, bind the expression i get an error
TestComponent:
#using System.Linq.Expressions;
#using System.Reflection;
#code
{
[Parameter]
Expression<Func<string>> For { get; set; }
protected override void OnInit()
{
var propertyInfo = ((MemberExpression)For.Body).Member as PropertyInfo;
var me = (MemberExpression)((MemberExpression)For.Body).Expression;
var ce = (ConstantExpression)me.Expression;
var fieldInfo = ce.Value.GetType().GetField(me.Member.Name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
var thisObject = fieldInfo.GetValue(ce.Value);
}
}
WrapperComponent
#using Models
<TestComponent For="#(() => Obj.Name)"></TestComponent>
#code
{
[Parameter]
TestModel Obj { get; set; }
}
TestPage
#page "/test"
<TestComponent For="#(() => obj.Name)"></TestComponent>
<WrapperComponent Obj="#obj"></WrapperComponent>
#code
{
TestModel obj = new TestModel();
}
Running only the first component, TestComponent, works fine.
If I run the second component instead, WrapperComponent, I get the following:
NullReferenceException: Object reference not set to an instance of an object.
CustomerportalCore.Components.TestComponent.OnInit() in TestComponent.razor
var thisObject = fieldInfo.GetValue(ce.Value);
Microsoft.AspNetCore.Components.ComponentBase.RunInitAndSetParametersAsync()
Microsoft.AspNetCore.Components.Server.Circuits.CircuitPrerenderer.CircuitHost_UnhandledException(object sender, UnhandledExceptionEventArgs e)
Microsoft.AspNetCore.Components.Server.Circuits.CircuitHost.Renderer_UnhandledException(object sender, Exception e)
Microsoft.AspNetCore.Components.Browser.Rendering.RemoteRenderer.HandleException(Exception exception)
Microsoft.AspNetCore.Components.Rendering.Renderer.AddToPendingTasks(Task task)
Microsoft.AspNetCore.Components.Rendering.ComponentState.SetDirectParameters(ParameterCollection parameters)
Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InitializeNewComponentFrame(ref DiffContext diffContext, int frameIndex)
Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InitializeNewSubtree(ref DiffContext diffContext, int frameIndex)
Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InsertNewFrame(ref DiffContext diffContext, int newFrameIndex)
Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.AppendDiffEntriesForRange(ref DiffContext diffContext, int oldStartIndex, int oldEndIndexExcl, int newStartIndex, int newEndIndexExcl)
Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.ComputeDiff(Renderer renderer, RenderBatchBuilder batchBuilder, int componentId, ArrayRange<RenderTreeFrame> oldTree, ArrayRange<RenderTreeFrame> newTree)
Microsoft.AspNetCore.Components.Rendering.ComponentState.RenderIntoBatch(RenderBatchBuilder batchBuilder, RenderFragment renderFragment)
Microsoft.AspNetCore.Components.Rendering.Renderer.RenderInExistingBatch(RenderQueueEntry renderQueueEntry)
Microsoft.AspNetCore.Components.Rendering.Renderer.ProcessRenderQueue()
Microsoft.AspNetCore.Components.Server.Circuits.CircuitPrerenderer.CircuitHost_UnhandledException(object sender, UnhandledExceptionEventArgs e)
Microsoft.AspNetCore.Components.Server.Circuits.CircuitHost.Renderer_UnhandledException(object sender, Exception e)
Microsoft.AspNetCore.Components.Browser.Rendering.RemoteRenderer.HandleException(Exception exception)
Microsoft.AspNetCore.Components.Rendering.Renderer.ProcessRenderQueue()
Microsoft.AspNetCore.Components.Rendering.Renderer.AddToRenderQueue(int componentId, RenderFragment renderFragment)
Microsoft.AspNetCore.Components.RenderHandle.Render(RenderFragment renderFragment)
Microsoft.AspNetCore.Components.ComponentBase.StateHasChanged()
Microsoft.AspNetCore.Components.ComponentBase.CallOnParametersSetAsync()
Microsoft.AspNetCore.Components.ComponentBase.RunInitAndSetParametersAsync()
Microsoft.AspNetCore.Components.Server.Circuits.CircuitPrerenderer.CircuitHost_UnhandledException(object sender, UnhandledExceptionEventArgs e)
Microsoft.AspNetCore.Components.Server.Circuits.CircuitHost.Renderer_UnhandledException(object sender, Exception e)
Microsoft.AspNetCore.Components.Browser.Rendering.RemoteRenderer.HandleException(Exception exception)
Microsoft.AspNetCore.Components.Rendering.Renderer.AddToPendingTasks(Task task)
Microsoft.AspNetCore.Components.Rendering.ComponentState.SetDirectParameters(ParameterCollection parameters)
Microsoft.AspNetCore.Components.Rendering.Renderer.RenderRootComponentAsync(int componentId, ParameterCollection initialParameters)
Microsoft.AspNetCore.Components.Rendering.HtmlRenderer.CreateInitialRenderAsync(Type componentType, ParameterCollection initialParameters)
Microsoft.AspNetCore.Components.Rendering.HtmlRenderer.RenderComponentAsync(Type componentType, ParameterCollection initialParameters)
Microsoft.AspNetCore.Components.Server.Circuits.CircuitHost+<>c__DisplayClass41_0+<<PrerenderComponentAsync>b__0>d.MoveNext()
Microsoft.AspNetCore.Components.Rendering.RendererSynchronizationContext+<>c__11<TResult>+<<InvokeAsync>b__11_0>d.MoveNext()
Microsoft.AspNetCore.Components.Server.Circuits.CircuitPrerenderer.PrerenderComponentAsync(ComponentPrerenderingContext prerenderingContext)
Microsoft.AspNetCore.Mvc.Rendering.HtmlHelperComponentPrerenderingExtensions.RenderComponentAsync<TComponent>(IHtmlHelper htmlHelper, object parameters)
CustomerportalCore.Pages.Pages__Host.<ExecuteAsync>b__22_1() in _Host.cshtml
#(await Html.RenderComponentAsync<App>())</App>
Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperExecutionContext.SetOutputContentAsync()
CustomerportalCore.Pages.Pages__Host.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.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()
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.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
What am I missing?
I'm no expert with Blazor, but if you invoke the expression in OnInit instead of reflecting, it seems to give me a sensible answer:
For.Compile().Invoke()
gives me "testing, testing", which is what I gave my model as a Name. This might be horrible advice, or have some unknown horrors built in though ¯(ツ)/¯
A quick search shows that there might be some memory issues by creating and evaluating a lot of Expression/Funcs, so that might be something to consider