Threading issue when using IViewComponentHelper to convert ViewComponent to HTML string - c#

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?

Related

How can to map to a wrapper class using Mapster?

Based on my project I need to create a wrapper for “IFormFile”, Actually I created a “AppFileProxy” class and “IAppFile” interface for this purpose :
IAppFile.cs :
public interface IAppFile
{
string Name { get; }
string FileName { get; }
string ContentType { get; }
long Length { get; }
void CopyTo(Stream target);
Task CopyToAsync(Stream target, CancellationToken cancellationToken = default);
Stream OpenReadStream();
}
AppFileProxy.cs :
public class AppFileProxy : IAppFile
{
private readonly IFormFile _formFile;
public AppFileProxy(IFormFile formFile)
{
_formFile = formFile ?? throw new ArgumentNullException(nameof(formFile));
}
public string Name => _formFile.Name;
public string FileName => _formFile.FileName;
public string ContentType => _formFile.ContentType;
public long Length => _formFile.Length;
public void CopyTo(Stream target)
{
_formFile.CopyTo(target);
}
public Task CopyToAsync(Stream target, CancellationToken cancellationToken = default)
{
return _formFile.CopyToAsync(target, cancellationToken);
}
public Stream OpenReadStream()
{
return _formFile.OpenReadStream();
}
}
Now, I want to Map “IFormFile” to “IAppFile” by using Mapster in the action controller as shown below :
CompanyDto.cs :
public class CompanyDto
{
public string Name { get; set; }
public IFormFile Logo { get; set; }
}
CompanyMapDto.cs :
public class CompanyMapDto : IRegister
{
public int Id { get; set; }
public string Name { get; set; }
public IAppFile Logo { get; set; }
public void Register(TypeAdapterConfig config)
{
config.ForType<CompanyDto, CompanyMapDto>()
.Map(dest => dest.Logo, src => new AppFileProxy(src.Logo));
}
}
action controller :
[HttpPost]
[Route("[controller]/[action]")]
public async Task<IActionResult> AddCompanyWithLogo([FromForm]CompanyDto dto)
{
CompanyMapDto company = dto.Adapt<CompanyMapDto>();
var stream = company.Logo.OpenReadStream();
return Ok();
}
But When I call action I get exception error for OpenReadStream() method :
System.NotImplementedException: The method or operation is not implemented.
at GeneratedType_1.OpenReadStream()
at MapsterInDotNet.Controllers.CompaniesController.AddCompanyWithLogo(CompanyDto dto) in C:\Users\Mohsen\source\repos\UseMapsterInDotNet\MapsterInDotNet\MapsterInDotNet\Controllers\CompaniesController.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|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)
How do I resolve this?
Well. I managed to make it work. You have to explicitly configurate mapping from IAppFile to IFormFile.
So instead of your configuration:
config.ForType<CompanyDto, CompanyMapDto>()
.Map(dest => dest.Logo, src => new AppFileProxy(src.Logo));
Use this:
TypeAdapterConfig<IFormFile, IAppFile>.ForType() // Or NewConfig()
.MapWith(src => new AppFileProxy(src));

What is the reason for this error? (.Net 5, 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}")]

JWT: 'System.String' has three segments but is not in proper JWS format

I have an idToken string that is returned by google-sign-in use in mobile app with flutter and firebase:
Code in flutter
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/cupertino.dart';
import 'package:google_sign_in/google_sign_in.dart';
class Authentication {
static GoogleSignIn googleSignIn;
static Future<User> signInWithGoogle(BuildContext context) async {
FirebaseAuth auth = FirebaseAuth.instance;
User user;
googleSignIn = GoogleSignIn();
final GoogleSignInAccount googleSignInAccount = await googleSignIn.signIn();
if (googleSignInAccount != null) {
final GoogleSignInAuthentication googleSignInAuthentication =
await googleSignInAccount.authentication;
final AuthCredential credential = GoogleAuthProvider.credential(
accessToken: googleSignInAuthentication.accessToken,
idToken: googleSignInAuthentication.idToken,
);
try {
final UserCredential userCredential =
await auth.signInWithCredential(credential);
user = userCredential.user;
} on FirebaseAuthException catch (e) {
if (e.code == 'account-exists-with-different-credential') {
// handle the error here
} else if (e.code == 'invalid-credential') {
// handle the error here
}
} catch (e) {
// handle the error here
}
print("Credential token: ${credential.token}");
print("Credential provider id: ${credential.providerId}");
print("AccessToken: ${googleSignInAuthentication.accessToken}");
print("ID Token: ${googleSignInAuthentication.idToken}");
print("AccessToken.length: ${googleSignInAuthentication.accessToken.length}");
print("IdToken.length: ${googleSignInAuthentication.idToken.length}");
}
return user;
}
static Future signOut() async {
await googleSignIn.signOut();
FirebaseAuth.instance.signOut();
}
}
ID token is returned.
And I use this code to decode it:
public JwtPayload PayloadInfo(string idToken)
{
var jwtToken = new JwtSecurityToken(idToken);
JwtPayload payload = jwtToken.Payload;
return payload;
}
It works fine in the console app but with the .net 5 web API it fail with error:
System.ArgumentException: IDX12739: JWT: 'System.String' has three segments but is not in proper JWS format.
I research that my idToken is not in JWS type... and I don't know how to solve this.
Weirdly, the function PayloadInfo works fine in C# console app but in the web API, it doesn't.
Controller
[HttpPost("login-google")]
[MapToApiVersion("1.0")]
public async Task<IActionResult> GoogleLoginAsync(
[FromBody] ExternalAuthModel model)
{
if (ModelState.IsValid)
{
var result = await
_userService.GoogleExternalLoginAsync(model);
if (result.IsSuccess)
{
return Ok(result);
}
return BadRequest(result);
}
return BadRequest("Somethings going wrong...");
}
ExternalAuthModel
public class ExternalAuthModel
{
public string Provider { get; set; }
public string IdToken { get; set; }
}
GoogleExternalLoginAsync function in my Service
public async Task<UserManagerResponse> GoogleExternalLoginAsync(ExternalAuthModel model)
{
var payload = _jwtHandler.PayloadInfo(model.IdToken);
if (payload is null)
{
return new UserManagerResponse
{
Message = "Invalid google authentication.",
IsSuccess = false
};
}
var info = new UserLoginInfo(model.Provider, payload.Sub, model.Provider);
var user = await _userManager.FindByLoginAsync(info.LoginProvider, info.ProviderKey);
if (user is null)
{
user = await _userManager.FindByEmailAsync(payload["email"].ToString());
await _userManager.CreateAsync(user);
if (!await _roleManager.RoleExistsAsync(UserRoles.User))
await _roleManager.CreateAsync(new IdentityRole(UserRoles.User));
await _userManager.AddToRoleAsync(user, UserRoles.User);
await _userManager.AddLoginAsync(user, info);
}
else
{
await _userManager.AddLoginAsync(user, info);
}
if (user is null)
{
return new UserManagerResponse
{
Message = "Invalid google authentication.",
IsSuccess = false
};
}
var token = await _jwtHandler.GenerateToken(user);
return new UserManagerResponse
{
Message = token[0],
IsSuccess = true,
ExpireDate = DateTime.Parse(token[1])
};
}
PayloadInfo function
public JwtPayload PayloadInfo(string idToken)
{
// Exception when excute this line... it says my idToken is not in
// JWS compact format....
var jwtToken = new JwtSecurityToken(idToken);
JwtPayload payload = jwtToken.Payload;
return payload;
}
Log...
2021-07-04T16:10:30.3810628+07:00 [ERR] An unhandled exception has occurred while executing the request. (48a46595)
System.ArgumentException: IDX12739: JWT: 'System.String' has three segments but is not in proper JWS format.
at System.IdentityModel.Tokens.Jwt.JwtSecurityToken..ctor(String jwtEncodedString)
at FTask.AuthServices.Helpers.JwtHandler.PayloadInfo(String idToken) in D:\cn7\Project\hao\ftask\FTask.AuthServices\Helpers\JwtHandler.cs:line 83
at FTask.AuthServices.Services.UserService.GoogleExternalLoginAsync(ExternalAuthModel model) in D:\cn7\Project\hao\ftask\FTask.AuthServices\Services\UserService.cs:line 163
at FTask.Api.Controllers.AuthController.GoogleLoginAsync(ExternalAuthModel model) in D:\cn7\Project\hao\ftask\FTask.Api\Controllers\AuthController.cs:line 109
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()
--- 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.Authentication.AuthenticationMiddleware.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)
Please test this:
public JwtPayload GetPayload()
{
var token = "<your token>";
var handler = new JwtSecurityTokenHandler();
var tokenData = handler.ReadJwtToken(token);
return tokenData.Payload;
}
i tested your token in .Net 5 Web API and got this result:

Blazor | Dependency Injection error: Cannot resolve scoped service

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)

Polymorphic model binding for generic type parameter

I'm sending a partial object along with a file.
var formData = new FormData();
formData.append('model', JSON.stringify({ ... }));
formData.append('file', file, file.name)
// send formData to backend
My controller method is using Delta<T> from OData.
[HttpPatch("{id}")]
public async Task<IActionResult> Patch(
[FromRoute] Guid id,
[ModelBinder(BinderType = typeof(FormDataJsonBinder))] Delta<AbstractModel> model,
IFormFile file = null
)
However I'm not sending Delta<AbstractModel> as AbstractModel is an abstract class. So I'm really sending Delta<DerivedModel> or Delta<AnotherDerivedModel> etc...
My problem is that ASP.NET keeps throwing saying that it cannot cast to Delta<DerivedModel>
System.InvalidCastException: Unable to cast object of type 'Microsoft.AspNet.OData.Delta`1[DerivedModel]' to type 'Microsoft.AspNet.OData.Delta`1[AbstractModel]'.
at lambda_method308(Closure , Object , Object[] )
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)
Here's my FormDataJsonBinder
public class FormDataJsonBinder : IModelBinder
{
public async Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null) throw new ArgumentNullException(nameof(bindingContext));
// Fetch the value of the argument by name and set it to the model state
string fieldName = bindingContext.FieldName;
var valueProviderResult = bindingContext.ValueProvider.GetValue(fieldName);
if (valueProviderResult == ValueProviderResult.None) return Task.CompletedTask;
else bindingContext.ModelState.SetModelValue(fieldName, valueProviderResult);
// Do nothing if the value is null or empty
string value = valueProviderResult.FirstValue;
if (string.IsNullOrEmpty(value)) return Task.CompletedTask;
try
{
// Delta is a special case
if (bindingContext.ModelType.IsAssignableTo(typeof(Delta)))
{
var jsonObject = JObject.Parse(value);
// This extracts type T from Delta<T>
var innerModelType = bindingContext.ModelType.GenericTypeArguments.First();
if (jsonObject["#odata.type"] is not null)
{
var odataType = jsonObject["#odata.type"].Value<string>();
innerModelType = Type.GetType(odataType);
}
var innerModel = JsonConvert.DeserializeObject(value, innerModelType);
var deltaType = typeof(Delta<>).MakeGenericType(innerModelType);
var delta = Activator.CreateInstance(deltaType) as IDelta;
foreach (var property in jsonObject.Properties())
{
delta.TrySetPropertyValue(property.Name, innerModel.GetType().GetProperty(property.Name)?.GetValue(innerModel));
}
bindingContext.Result = ModelBindingResult.Success(delta);
}
else
{
// Deserialize the provided value and set the binding result
var result = JsonConvert.DeserializeObject(value, bindingContext.ModelType);
bindingContext.Result = ModelBindingResult.Success(result);
}
}
catch (JsonException)
{
bindingContext.Result = ModelBindingResult.Failed();
}
return Task.CompletedTask;
}
}
I also tried using a IModelBinderProvider as recommended here, but that also just throws "cannot cast to Delta<DerivedModel>"
The solution was to create the Delta object the right way.
var delta = Activator.CreateInstance(bindingContext.ModelType, innerModelType) as IDelta;

Categories

Resources