SassKit.Multitenancy not compatible with AspNetCore 2.2? - c#

I've created a .NET Core API Controller, and in the POST method, I'm trying to use the CreatedAtActionResult method to include the route as a Location Header in my response.
[ApiController, Route("v1/[controller]")]
public class WidgetController: ControllerBase
{
public WidgetController(IWidgetService service)
{
_service = service;
}
private readonly IWidgetService _service;
[HttpGet("{id}", Name = "GetSingle")]
public IActionResult GetSingle(Guid id)
{
var result = _service.Get(id);
return Ok(result);
}
[HttpPost]
public IActionResult Post(WidgetModel model)
{
var result = _service.Post(model);
return result == Guid.Empty
? (IActionResult) BadRequest("No changes saved.")
: CreatedAtAction(nameof(GetSingle),
new {id = result},
model);
}
}
When I start the application, the first call to POST from POSTman runs without problem. Both the object and the Location Header URL get generated as expected. However, if I try to hit that endpoint a second time while the code is still running, I get the following error:
System.InvalidOperationException: No service for type 'Microsoft.AspNetCore.Routing.IEndpointAddressScheme1[Microsoft.AspNetCore.Routing.RouteValuesAddress]' has been registered.
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
at Microsoft.AspNetCore.Routing.DefaultLinkGenerator.GetEndpoints[TAddress](TAddress address)
at Microsoft.AspNetCore.Routing.DefaultLinkGenerator.GetPathByAddress[TAddress](HttpContext httpContext, TAddress address, RouteValueDictionary values, RouteValueDictionary ambientValues, Nullable1 pathBase, FragmentString fragment, LinkOptions options)
at Microsoft.AspNetCore.Routing.LinkGeneratorRouteValuesAddressExtensions.GetPathByRouteValues(LinkGenerator generator, HttpContext httpContext, String routeName, Object values, Nullable1 pathBase, FragmentString fragment, LinkOptions options)
at Microsoft.AspNetCore.Mvc.Routing.EndpointRoutingUrlHelper.Action(UrlActionContext urlActionContext)
at Microsoft.AspNetCore.Mvc.UrlHelperExtensions.Action(IUrlHelper helper, String action, String controller, Object values, String protocol, String host, String fragment)
at Microsoft.AspNetCore.Mvc.UrlHelperExtensions.Action(IUrlHelper helper, String action, String controller, Object values, String protocol, String host)
at Microsoft.AspNetCore.Mvc.CreatedAtActionResult.OnFormatting(ActionContext context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ObjectResultExecutor.ExecuteAsync(ActionContext context, ObjectResult result)
at Microsoft.AspNetCore.Mvc.ObjectResult.ExecuteResultAsync(ActionContext context)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeResultAsync(IActionResult result)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResultFilterAsync[TFilter,TFilterAsync]()
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResultExecutedContext context)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeResultFilters()
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter()
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync()
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync()
at Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext)
at Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware.Invoke(HttpContext httpContext)
at SaasKit.Multitenancy.Internal.TenantResolutionMiddleware1.Invoke(HttpContext context, ITenantResolver`1 tenantResolver)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
I have tried swapping out the CreatedAtAction with an Ok, and that 200 result will return as many times as I click the button in POSTman.
The code inside the Post method successfully processes, and it will move onto the OnActionExecuted method of a Filter that I created. I've tried looking through all of the properties of the ActionExecutedContext object and I don't see anything out of the ordinary. Once I get out of that empty OnActionExecuted method, the call returns the 500 status code and the above stack trace inside the error page. I do have an Exception filter, but that doesn't get touched.
Has anyone had issues with this before?
For reference, here is my Startup Configuration:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddMultitenancy<AppTenant, CachingAppTenantResolver>();
services.AddAutoMapper()
.AddSingleton(ConfigureAutoMapper())
.AddMvc(options =>
{
options.Filters.Add<ValidatorActionFilter>();
options.Filters.Add<ErrorHandlingFilter>();
})
.AddFluentValidation(validation => {
validation.RunDefaultMvcValidationAfterFluentValidationExecutes = false;
validation.ImplicitlyValidateChildProperties = true;
validation.RegisterValidatorsFromAssemblyContaining<WidgetModelValidator>();
})
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
.ConfigureApiBehaviorOptions(options =>
{
options.SuppressModelStateInvalidFilter = true;
options.SuppressMapClientErrors = true;
});
services.AddEntityFrameworkSqlServer()
.AddDbContext<MyContext>();
services.Configure<MultitenancyOptions>(configuration.GetSection("Multitenancy"));
services.AddCors(options =>
{
options.AddDefaultPolicy(
builder =>
{
builder.WithOrigins("http://localhost:4200").AllowAnyHeader().AllowAnyMethod();
});
});
ConfigureContainer(container);
return provider;
}

Try setting CompatibilityVersion.Version_2_0 or 2.1 instead of 2.2?
EndpointRouting is quite a big change under the covers of 2.2, and your 3rd party add-on might not be compatible.
Setting compatibility back to 2.1 will typically not require any code changes in your controller, so it's fairly low-cost.

Related

.NET 6 API System.InvalidOperationException

I have Autofac module like this on one class;
public class AutofacBusinessModule:Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<ProductManager>().As<IProductService>();
builder.RegisterType<EfProductDal>().As<IProductDal>();
builder.RegisterType<CategoryManager>().As<ICategoryService>();
builder.RegisterType<EfCategoryDal>().As<ICategoryDal>();
builder.RegisterType<CustomerManager>().As<ICustomerService>();
builder.RegisterType<EfCustomerDal>().As<ICustomerDal>();
builder.RegisterType<RegionManager>().As<IRegionService>();
builder.RegisterType<EfRegionDal>().As<IRegionDal>();
builder.RegisterType<TerritoryManager>().As<ITerritoryService>();
builder.RegisterType<EfTerritoryDal>().As<ITerritoryDal>();
builder.RegisterType<ShipperManager>().As<IShipperService>();
builder.RegisterType<EfShipperDal>().As<IShipperDal>();
builder.RegisterType<EmployeeManager>().As<IEmployeeDal>();
builder.RegisterType<EfEmployeeDal>().As<IEmployeeDal>();
var assembly = System.Reflection.Assembly.GetExecutingAssembly();
builder.RegisterAssemblyTypes(assembly).AsImplementedInterfaces()
.EnableInterfaceInterceptors(new ProxyGenerationOptions()
{
Selector = new AspectInterceptorSelector()
}).SingleInstance();
}
my api code its there;
[Route("api/[controller]")]
[ApiController]
public class ProductsController : Controller
{
private readonly IProductService _productService;
public ProductsController(IProductService productService)
{
_productService = productService;
}
[HttpGet("getall")]
public IActionResult GetAllProducts()
{
var result = _productService.GetAll();
if (result.Success)
{
return Ok(result);
}
return BadRequest(result);
}
}
}
I add this on program.cs but didn't work, if lower I use .net 6 i fix it like that but i dont know how to fix .net 6 because startup doesnt exists anymore.
IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
.ConfigureContainer<ContainerBuilder>(builder =>
{
builder.RegisterModule(new AutofacBusinessModule());
});
How can I fix this?
it gives me that error
System.InvalidOperationException: Unable to resolve service for type 'TAO.Business.Abstract.IProductService' while attempting to activate 'TAO.WebApi.Controllers.ProductsController'.
at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, Boolean isDefaultParameterRequired)
at lambda_method3(Closure , IServiceProvider , Object[] )
at Microsoft.AspNetCore.Mvc.Controllers.ControllerActivatorProvider.<>c__DisplayClass7_0.b__0(ControllerContext controllerContext)
at Microsoft.AspNetCore.Mvc.Controllers.ControllerFactoryProvider.<>c__DisplayClass6_0.g__CreateController|0(ControllerContext controllerContext)
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.g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.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)
HEADERS
=======
Accept: */*
Connection: keep-alive
Host: localhost:7019
User-Agent: PostmanRuntime/7.30.0
Accept-Encoding: gzip, deflate, br
Postman-Token: fbff062e-ca49-4f37-afc5-e8785afbd43c
Try the following code from migration doc:
builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
// Register services directly with Autofac here. Don't
// call builder.Populate(), that happens in AutofacServiceProviderFactory.
builder.Host.ConfigureContainer<ContainerBuilder>(builder => builder.RegisterModule(new AutofacBusinessModule()));
Note that the "old" generic hosting model still works in .NET 6, there is no requirement to use the new minimal hosting model (but you need to copy not only CreateHostBuilder method but also contents of old Program.Main into the new Program top-level statement file).

Unable to resolve service DbContext while attempting to activate controller

I have my own DbContext:
public class DreamsContext : DbContext
{
public DbSet<UserAccount> UserAccounts { get; set; }
public DbSet<DreamPublication> DreamPublications { get; set; }
public DreamsContext(DbContextOptions<DreamsContext> options) : base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<UserAccount>().ToTable("dreams_user");
modelBuilder.Entity<DreamPublication>().ToTable("dream_publications");
base.OnModelCreating(modelBuilder);
}
}
where UserAccount and DreamPublication contain just a few fields with get and set.
In my startup I add this for the DbContext:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<Models.DreamsContext>(options =>
options.UseSqlServer("server = SCAT\\SQLEXPRESS; database = dreams_web; Trusted_Connection=True ; MultipleActiveResultSets = true"));
}
And then I'm trying to inject my DbContext into a controller using DI:
private readonly Models.DreamsContext _context;
public SignUpController (Models.DreamsContext dbContext)
{
_context = dbContext;
}
But when I am trying to do something with this context I get an exception:
Unable to resolve service for type '(My DbContext)' while attempting to activate '(My controller)'
And I don't know what to do, on MSDN they do just this and everything works
Update. This is what written in console
System.InvalidOperationException: Unable to resolve service for type 'DreamWeb.Models.DreamsContext' while attempting to activate 'DreamWeb.Controllers.SignUpController'.
at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, Boolean isDefaultParameterRequired)
at lambda_method25(Closure , IServiceProvider , Object[] )
at Microsoft.AspNetCore.Mvc.Controllers.ControllerActivatorProvider.<>c__DisplayClass7_0.<CreateActivator>b__0(ControllerContext controllerContext)
at Microsoft.AspNetCore.Mvc.Controllers.ControllerFactoryProvider.<>c__DisplayClass6_0.<CreateControllerFactory>g__CreateController|0(ControllerContext controllerContext)
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.<InvokeNextResourceFilter>g__Awaited|25_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.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
The main problem was I was trying to configure services in Startup class, while I am using asp.net CORE so the main magic is going in program.cs
I moved everything to program.cs and everything is working fine. It cost me a few days, even it's such a little mistake
https://learn.microsoft.com/en-us/dotnet/architecture/porting-existing-aspnet-apps/app-startup-differences
According to this, startup should continue to work in asp.net core, but i had problems with it
I had the same problem I solved by adding the connection to the db in the main file of the Project Program.cs , add it after the line var builder :
// db connection
builder.Services.AddDbContext<Dbcontexclass>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnectionString"));
Add in appsettings.json :
"ConnectionStrings": {
"DefaultConnectionString": "SERVER=server;DATABASE=database;User ID=user;PASSWORD=password;"
}
fill the Connection String , Dbcontexclass , and it should work, I leave you the docs link ( https://learn.microsoft.com/en-us/aspnet/core/tutorials/first-mvc-app/working-with-sql?view=aspnetcore-7.0&tabs=visual-studio )

I can't get records from .net core mvc web api database

I couldn't solve it in any way, can you please help?
I added web api to my .net core mvc project. I can return values as string or json, quite normally. But when it comes to the database, I have a problem. I am getting a null error. No matter how hard I searched, I couldn't figure it out. The smallest answer helps a lot.
[ApiController] When I add it, my app doesn't open at all. When I make a comment line, it opens. But I can't call database methods. The same operations can be called seamlessly in the webui layer.
Startup.cs
Appsettings
Can you please help?
Fail:
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 zfc.webapi.Controllers.zfc.GetReferrer() in C:\Users\mderv\Desktop\zfc\zfc.webapi\Controllers\zfc.cs:line 26
at lambda_method(Closure , Object , Object[] )
at Microsoft.Extensions.Internal.ObjectMethodExecutor.Execute(Object target, Object[] parameters)
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.SyncActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeActionMethodAsync()
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeNextActionFilterAsync()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<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 Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
Csproj
Repository
From your screenshots and error so far I am assuming you haven't register the service in startup.cs file correctly.
Here I am adding a complete example for you how you can access data from database using your architecture.
Abstract:
public interface IChatRepository
{
object GetDataFromDatabase();
}
Concrete:
public class ChatRepository : IChatRepository
{
private readonly AppDbContext _dbContext;
public ChatRepository(AppDbContext dbContext)
{
this._dbContext = dbContext;
}
public object GetDataFromDatabase()
{
var dataFromDatabase = _dbContext.PrinterJobs.ToList();
return dataFromDatabase;
}
}
Note: I have injected a dbContext class instance here to access database object. This dbContext, IChatRepository and ChatRepository need to be registered in startup.cs file.
Startup:
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options => options.AddPolicy("AllowAll", p => p.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()));
services.AddScoped<IChatRepository, ChatRepository>();
services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddMvc().AddRazorPagesOptions(options =>
{
options.Conventions.ConfigureFilter(new IgnoreAntiforgeryTokenAttribute());
});
}
AppDbContext:
public class AppDbContext: DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
{
}
public DbSet<PrinterJob> PrinterJobs { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<PrinterJob>().ToTable("PrintJob");
}
internal object Query<T>(string v, string name, int employeeId)
{
throw new NotImplementedException();
}
}
PrinterJob sample model class:
public class PrinterJob
{
[Key]
public int PrinterId { get; set; }
public string PrinterName { get; set; }
public int PrintedBy { get; set; }
public int TotalPrint { get; set; }
}
Database script:
CREATE TABLE PrintJob
(
[PrinterId] [int] PRIMARY KEY IDENTITY(1,1) NOT NULL,
[PrinterName] [nvarchar](100) NULL,
[PrintedBy] [int] NULL,
[TotalPrint] [int] NULL,
)
Note: add some sample data into the table once you create the table from about script.
appsettings.json:
"ConnectionStrings": {
"DefaultConnection": "Server=YourServerName;Database=YourDatabaseName;Trusted_Connection=True;MultipleActiveResultSets=true"
}
Note: make sure you are referring a correct database to access your data accordingly.
Controller:
[Route("api/ZfcData")]
public class ZfcDataController : Controller
{
private readonly IChatRepository _chatRepository;
public ZfcDataController(IChatRepository chatRepository)
{
this._chatRepository = chatRepository;
}
[HttpGet("[action]")]
[Route("GetDataFromDatabase")]
[ActionName("GetDataFromDatabase")]
public object GetDataFromDatabase()
{
var callRepository = _chatRepository.GetDataFromDatabase();
return Ok(callRepository);
}
}
Output:
Hope it would guide you through, and help you to get resolve your problem and implementations.
You are using dependecy injection to use your chatRepository and the injection it's not well configured ,
services.AddScoped<InterfaceOfMyReposiory,ImplementationOfMyRepository>();
So let's suppose that your ChatRepository is :
public class ChatRepository :IChatRepository {
//some special impelementation
}
and you have an interface like this :
public interface IChatRepository {
// some great methods definitions
}
so in your startup.cs class you should configure it like this :
services.AddScoped<IChatRepository ,ChatRepository>();
you can check more in details here.
in your case this should solve the null exception :
ChatRepository : interface
EfChatRepository and EfGenericRepository : implementation
services.AddScoped<ChatRepository ,EfChatRepository>();
EfChatRepository inherit the implemntation of EfGenericRepository

NullReferenceException from JsonSerializer in POST method

I'm trying to write a simple REST API in #C, but I ran into a problem with a rather unhelpful error message very early when writing a POST handler. I'm using .NET Core 3.0 and the project was created with the ASP.NET Core API template in Visual Studio.
This is a simplified version of my code that still triggers the issue (the classes are in separate Files in the full project):
[Route("api/blub")]
[ApiController]
public class BlubController : ControllerBase
{
[HttpGet]
public IEnumerable<Blub> Get()
{
return new Blub[0];
}
[HttpPost]
public ActionResult<Blub> PostBlub([FromBody] string[] paths)
{
return new Blub(paths);
}
}
public class Blub
{
public Blub(string[] paths)
{
this.Paths = paths;
StartedAt = DateTime.Now;
}
public string[] Paths { get; }
public DateTime StartedAt { get; }
}
The payload of my POST request is something like the following:
{ "paths": [ "abc", "def" ] }
I'm getting the following Exception when performing a POST request to my api/blub route:
System.NullReferenceException: Object reference not set to an instance of an object.
at System.Text.Json.JsonSerializer.HandleStartObject(JsonSerializerOptions options, ReadStack& state)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadCore(JsonReaderState& readerState, Boolean isFinalBlock, ReadOnlySpan`1 buffer, JsonSerializerOptions options, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadAsync[TValue](Stream utf8Json, Type returnType, JsonSerializerOptions options, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonInputFormatter.ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
at Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonInputFormatter.ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
at Microsoft.AspNetCore.Mvc.ModelBinding.Binders.BodyModelBinder.BindModelAsync(ModelBindingContext bindingContext)
at Microsoft.AspNetCore.Mvc.ModelBinding.ParameterBinder.BindModelAsync(ActionContext actionContext, IModelBinder modelBinder, IValueProvider valueProvider, ParameterDescriptor parameter, ModelMetadata metadata, Object value)
at Microsoft.AspNetCore.Mvc.Controllers.ControllerBinderDelegateProvider.<>c__DisplayClass0_0.<<CreateBinderDelegate>g__Bind|0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
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__Logged|17_1(ResourceInvoker invoker)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
It doesn't matter whether my POST request contains the correct body or not, any POST requests seems to trigger this exception. The GET request works without issues. I tried to log to the console and set a breakpoint in my function, but as far as I can tell the exception is thrown even before my function is called.
Why is the JsonFormatter throwing an exception here, and how can I fix this?
You have an issue in type mapping, either change method signature to:
[HttpPost]
public ActionResult<Blub> PostBlub([FromBody] MyRequest request)
{
return new Blub(request.Paths);
}
public class MyRequest
{
public string[] Paths { get; set; }
}
Or change the payload to:
[ "abc", "def" ]
This simply means that some member/variable of some reference type
is dereferenced by using and of its instance non-static members,
which requires this member/variable to be non-null, but in fact it
appears to be null. Simply if it execute it under debugger, it will
stop the execution where the exception is thrown. Put a break point on
that line, restart the application and come to this point again.
Evaluate all references involved in next line and see which one is
null while it needs to be not null. After you figure this out, fix the
code: either make sure the member/variable is properly initialized to
a non-null reference, or check it for null and, in case of null,
do something else.
Use the below code snippet:
[HttpPost]
public ActionResult<Blub> PostBlub([FromBody] APIRequest request)
{
return new Blub(request.Paths);
}
public class APIRequest
{
public string[] Paths { get; set; }
}

How to make autofac KeyFilter works in asp.net-core web api?

Cannot use KeyFilter attribute to resolve registered type in asp.net core web api 2.2
I wanna use Autofac to resolve different instance of a type. I registered type in Startup.ConfigureServices by using RegisterType().Keyed and RegisterType().Named.
I can use IContainer.ResolveKeyed to resolve instance, but can't use KeyFilter to resolve instance in constructor
Startup
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public static IContainer Container { get; private set; }
// This method gets called by the runtime. Use this method to add services to the container.
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2).AddControllersAsServices();
var builder = new ContainerBuilder();
builder.Populate(services);
builder.RegisterType<Foobar>().UsingConstructor(typeof(string)).WithParameter("name", "Eric").Named<Foobar>("Eric").SingleInstance();
builder.RegisterType<Foobar>().UsingConstructor(typeof(string)).WithParameter("name", "Fred").Keyed<Foobar>("Fred").SingleInstance();
Container = builder.Build();
var serviceProvider = new AutofacServiceProvider(Container);
return serviceProvider;
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseMvc();
}
}
ValuesController
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
private readonly Foobar fb1;
private readonly Foobar fb2;
public ValuesController([KeyFilter("Eric")]Foobar fbEric, [KeyFilter("Fred")]Foobar fbFred)
{
// KeyFilter not work
fb1 = fbEric;
fb2 = fbFred;
// Container.ResolvedKeyed work
fb1 = Startup.Container.ResolveKeyed<Foobar>("Eric");
fb2 = Startup.Container.ResolveNamed<Foobar>("Fred");
}
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
return new string[] { fb1.Say(), fb2.Say() };
}
}
Use KeyFilter will throw below exceptions:
An unhandled exception has occurred while executing the request.
Autofac.Core.DependencyResolutionException: An exception was thrown while activating Autofac.MI.WebApi.Controllers.ValuesController. ---> Autofac.Core.DependencyResolutionException: None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'Autofac.MI.WebApi.Controllers.ValuesController' can be invoked with the available services and parameters:
Cannot resolve parameter 'Autofac.MI.ClassLib.Foobar fbEric' of constructor 'Void .ctor(Autofac.MI.ClassLib.Foobar, Autofac.MI.ClassLib.Foobar)'.
at Autofac.Core.Activators.Reflection.ReflectionActivator.GetValidConstructorBindings(IComponentContext context, IEnumerable`1 parameters) in C:\projects\autofac\src\Autofac\Core\Activators\Reflection\ReflectionActivator.cs:line 160
at Autofac.Core.Activators.Reflection.ReflectionActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters) in C:\projects\autofac\src\Autofac\Core\Activators\Reflection\ReflectionActivator.cs:line 120
at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters, Object& decoratorTarget) in C:\projects\autofac\src\Autofac\Core\Resolving\InstanceLookup.cs:line 117
--- End of inner exception stack trace ---
at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters, Object& decoratorTarget) in C:\projects\autofac\src\Autofac\Core\Resolving\InstanceLookup.cs:line 135
at Autofac.Core.Resolving.InstanceLookup.Execute() in C:\projects\autofac\src\Autofac\Core\Resolving\InstanceLookup.cs:line 83
at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters) in C:\projects\autofac\src\Autofac\Core\Resolving\ResolveOperation.cs:line 131
at Autofac.Core.Resolving.ResolveOperation.Execute(IComponentRegistration registration, IEnumerable`1 parameters) in C:\projects\autofac\src\Autofac\Core\Resolving\ResolveOperation.cs:line 84
at Autofac.ResolutionExtensions.TryResolveService(IComponentContext context, Service service, IEnumerable`1 parameters, Object& instance) in C:\projects\autofac\src\Autofac\ResolutionExtensions.cs:line 1041
at Autofac.ResolutionExtensions.ResolveService(IComponentContext context, Service service, IEnumerable`1 parameters) in C:\projects\autofac\src\Autofac\ResolutionExtensions.cs:line 871
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
at Microsoft.AspNetCore.Mvc.Controllers.ServiceBasedControllerActivator.Create(ControllerContext actionContext)
at Microsoft.AspNetCore.Mvc.Controllers.ControllerFactoryProvider.<>c__DisplayClass5_0.<CreateControllerFactory>g__CreateController|0(ControllerContext controllerContext)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeInnerFilterAsync()
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter()
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync()
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync()
at Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
For KeyFilter, you need to register the service with WithAttributeFiltering.
For AddControllersAsServices, it only register the service to service collection, but it did not register with WithAttributeFiltering.
Try code below:
services.AddMvc().AddControllersAsServices().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
var builder = new ContainerBuilder();
builder.Populate(services);
builder.RegisterType<Foobar>().UsingConstructor(typeof(string)).WithParameter("name", "Eric").Named<Foobar>("Eric").SingleInstance();
builder.RegisterType<Foobar>().UsingConstructor(typeof(string)).WithParameter("name", "Fred").Keyed<Foobar>("Fred").SingleInstance();
var controllers = typeof(Startup).Assembly.GetTypes().Where(t => t.BaseType == typeof(ControllerBase)).ToArray(); // for api controller
//var controllers = typeof(Startup).Assembly.GetTypes().Where(t => t.BaseType == typeof(Controller)).ToArray(); // for mvc controller
builder.RegisterTypes(controllers).WithAttributeFiltering();
Container = builder.Build();

Categories

Resources