Fluxor Blazor error on assembly scanning and registration - c#

I've followed the steps of setting up a Fluxor library.
Added
var currentAssembly = typeof(Program).Assembly; builder.Services.AddFluxor(options => options.ScanAssemblies(currentAssembly));
into the Program.cs. Then added <Fluxor.Blazor.Web.StoreInitializer/> into App.Razor
Stater is decorated with [FeatureState] attribute. Everything according to documention. But the application fails to start with the message :
ArgumentException: An item with the same key has already been added. Key: Store.Account.AccountTopUpState
Seems like the problem exists in Fluxor assembly scanning ...

Are you also creating a class deriving from Feature<AccountTopUpState>? If so, remove the [FeatureState] attribute. I believe the attribute was added as an alternative to the Feature base class approach, and you should choose one approach or the other, but not both.

Related

Blazor Error: "There is no registered service of type" -- other StackOverflow questions do not solve

In my .Net CORE 5 (imported support files v5.0.12) Blazor PWA VS-2019 solution, I "had" a working 'Customer'-(data/app)service and Blazor pages to List and CRUD the Customer records (works as expected). I created similar 'Vehicle' files for both the SERVER-project and the CLIENT-project (of course changing the model field-references).
There are NO compilation errors yet, when I try to show the "VehicleList" page, this error appears in the Output-window:
crit:
Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
Unhandled exception rendering component: Cannot provide a value for property '_vehicleService' on type
'MyCore5AppPWA.Client.Pages.VehicleList'. There is no registered
service of type 'MyCore5AppPWA.Client.Services.IVehicleService'.
System.InvalidOperationException: Cannot provide a value for property
'_vehicleService' on type 'MyCore5AppPWA.Client.Pages.VehicleList'.
There is no registered service of type
'MyCore5AppPWA.Client.Services.IVehicleService'. at
Microsoft.AspNetCore.Components.ComponentFactory.<>c__DisplayClass6_0.g__Initialize|2(IServiceProvider
serviceProvider, IComponent component)
Please note the above notation of "...c__DisplayClass6_0..." that is curious to me (not knowing the significance of this).
I have read many of the similar questions/answers related to the subject of this post that do not correct the error.
Here is a snippet from the Startup.cs file:
public void ConfigureServices(IServiceCollection services) {
_ = services.AddDbContext<AppDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DbConnection")));
services.AddScoped<ICustomerRepository, CustomerRepository>();
services.AddScoped<IVehicleRepository, VehicleRepository>();
services.AddControllersWithViews();
services.AddRazorPages();
services.AddScoped<WeatherForecastService>();
}
Here is the snippet from the "VehicleList.razor' code file.
//html... declarations.
#layout MainLayout
#page "/vehiclelist"
#using MyCore5AppPWA.Client.Services;
#using MyCore5AppPWA.Shared
//...html omitted...//
#code {
[Inject]
private IVehicleService _vehicleService { get; set; }
[Inject]
private NavigationManager navigationManager { get; set; } ...other code...
I also have in the SERVER-project/Controllers subfolder a "CustomerController.cs" and a "VehicleController.cs".
Since I am rather new to Blazor/Core-5/PWA, I conclude that I am missing something regarding adding new service(s) to the PWA projects.
Your comments and suggestions are very welcome. thanks John
You are injecting a IVehicleService in your VehicleList.razor file. But it doesn't seem like you've registered any implementation of this interface in your DI container?
There is no registered service of type 'MyCore5AppPWA.Client.Services.IVehicleService
Something like
services.AddScoped<IVehicleService, YourImplementation>();
should solve it.
Note that you need to register it with the correct lifetime (Singleton, Scoped or Transient) depending on your implementation.
Dependency injection issues typically surface at runtime because the class consuming these services won’t know they aren’t registered to the container until they request them at runtime. In your case the exception is saying you forgot to register an implementation of IVehicleService. You can register it like any other service by calling .AddScoped<> to your ConfigureServices method.
Thanks to #JOSEFtw for his helpful replies. This led me to the solution to this question.
The Blazor PWA web-app has a SERVER project and a CLIENT-SIDE project. The question stated and #JOSEFtw pointed out that the 'issue' was with the 'Client.Services.IVehicleService' not being registered.
After my comments-thread with #JOSEFtw I thought that something that #JOSEFtw was trying to tell me was not in my realm of consciousness. I made "searches' into the VS-2019 source-files which showed that the client-services are registered in the CLIENT-project's Program.cs file. I discovered this by searching for "CustomerService" text and I found it there. The problem was solved by adding the "IVehicleService, VehicleService" references to the Program.cs file as follows:
builder.Services.AddHttpClient<IVehicleService, VehicleService>(client => {
client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress);
});
I mistakenly thought that the 'repository' interface and implementation classes were registered in the SERVER'S Startup.cs which had the newly added Vehicle-repository references, was all that was necessary to register the services (even client-side services -- me stupid). But I did not know about the Program.cs file for the registration of the client-side registration as a separate registration process.
My lower knowledge of Blazor PWA and C# contributed to this question and comments with #JOSEFtw. Of course we all learn from our mistakes. Thanks to all.

FluentValidation: How to register all validators automatically from another assembly?

I'm using "FluentValidation.AspNetCore" library (Version="8.6.2") for a .Net Core project.
What I would like to do is to register all my Validators automatically in Startup.cs class, using something like this (which is what I'm using now):
services.AddControllers().AddFluentValidation(fv => fv.RegisterValidatorsFromAssemblyContaining<Startup>());
But the problem is that my validators are going to be moved to another assembly (required by client), so I can't use Startup as reference for the registration.
Is there a way I can do this without having to register the validators one by one?
For registering Validator, there are three ways.
Registering each validator in Service with AddTransient.
Registering using “RegisterValidatorsFromAssemblyContaining” method registers all
validators derived from AbstractValidator class within the assembly
containing the specified type.
Registering using “RegisterValidatorsFromAssembly” method.
source here
If you use option number 2 and replace Startup in your code with any class derived from AbstractValidator from another assembly, it will register all validators from that assembly
Example:
services.AddControllers().AddFluentValidation(fv => fv.RegisterValidatorsFromAssemblyContaining<AnotherValidationClass>());
You can use the official nuget package for that:
services.AddValidatorsFromAssemblyContaining<SomeValidator>();
or
services.AddValidatorsFromAssemblyContaining(typeof(SomeValidator));
or
services.AddValidatorsFromAssembly(typeof(SomeValidator).Assembly);
All possible DI options described here
AddFluentValidation() is deprecated.
source : https://github.com/FluentValidation/FluentValidation/issues/1965
old:
builder.Services.AddControllersWithViews().AddFluentValidation(fv => { });//or AddMvc(), AddMvcCore()
//or
builder.Services.AddFluentValidation(config =>
{
config.ConfigureClientsideValidation(enabled: false);
});
new :
builder.Services.AddValidatorsFromAssemblyContaining<AnyValidator>() // register validators
builder.Services.AddFluentValidationAutoValidation(); // the same old MVC pipeline behavior
builder.Services.AddFluentValidationClientsideAdapters(); // for client side

Bot Framework v4.4.3 Update Skill Manifest Template

The document here says update skill manifest but does not specify how to add a new skill in the manifest file.
I have the following in the main dialog:
case MasterCollectionsLuis.Intent.PlayVideo:
{
turnResult = await dc.BeginDialogAsync(nameof(Water.PlayVideo.PlayVideoDialog));
break;
}
And have a base for PlayVideo and the Dialog itself as shown by the example SampleDialog and SampleDialogBase.
When I load the manifest file at http://localhost:1205/api/skill/manifest:
An unhandled exception occurred while processing the request.
InvalidOperationException: Unable to resolve service for type 'MasterCollections.Dialogs.Water.PlayVideo.PlayVideoDialog' while attempting to activate 'MasterCollections.Dialogs.MainDialog'.
Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(Type serviceType, Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, bool throwIfCallSiteNotFound)
Dependency Injection error
That error is to do with the dependency injection pipeline, without setting your Startup.cs file my best guess is that you haven't wired up PlayVideoDialog in there.
In your Startup.cs file you will have a section where you register your Dialogs against the dependency injection service provider like so:
services.AddTransient<CancelDialog>();
services.AddTransient<EscalateDialog>();
services.AddTransient<MainDialog>();
You simply need to add another line each time you add a new Dialog:
services.AddTransient<MyNewDialog>();
In your case you would have PlayVideoDialog in place of MyNewDialog.
Also make sure that you are not passing a PlayVideoDialog parameter into the constructor of MainDialog as this is not how Dialogs work, you should instead call the AddDialog(new PlayVideoDialog(...)) method inside the constructor of MainDialog.
Skills manifest question
I haven't created a skill myself but there is additional documentation which may or may not be helpful about adding skill support, adding skills, and the skills manifest file itself.
In the documentation that you linked it states:
this has been pre-populated with the Skill ID and name and a sample action which you can modify at this stage if required
which leads me to believe you can manually modify this file to fit your requirements, but you don't have to modify it if there are no changes required.

Problem generating Swagger definitions using custom naming strategy

I have an OData Web API and I'm using Swashbuckle and Swagger to generate and display Web API documentation. This was working and producing nice definition names, like so:
User
Role
Permission
ODataResponse[List[Permission]]
CoordinateSystem
Etc...
I ran into an issue with "Conflicting schemaIds" after adding some new objects and controllers and started getting this error:
System.InvalidOperationException: 'Conflicting schemaIds: Duplicate schemaIds detected for types Microsoft.Spatial.CoordinateSystem and MyProject.CoordinateSystem. See the config setting - "UseFullTypeNameInSchemaIds" for a potential workaround'
As the error states, I added the following line in SwaggerConfig.cs
c.UseFullTypeNameInSchemaIds();
This fixed the error but caused some issues with my definition names. Now they show up like this:
MyProject.User
MyProject.Role
MyProject.Permission
Swashbuckle.OData.ODataResponse[System.Collections.Generic.List[MyProject.Permission]]
MyProject.CoordinateSystem
Microsoft.Spatial.CoordinateSystem
The third last one is problematic now as it is too long for the app that reads this information.
Next, I tried using the custom strategy example provided in SwaggerConfig.cs to rename one of the conflicting definition names:
c.SchemaId(t => t.FullName.Contains("Microsoft.Spatial.CoordinateSystem")
? t.FullName : t.Name);
This works for the conflicting definitions as it uses the full name for "Microsoft.Spatial.CoordinateSystem" and I get this now:
User
Role
Permission
ODataResponse`1
CoordinateSystem
Microsoft.Spatial.CoordinateSystem
The problem now is "ODataResponse`1". I'm expecting "ODataResponse[List[Permission]]" but it is displaying the name of the Swashbuckle.OData definition only. There are other options - I tried t.FullName, t.Name, t.AssemblyQualifiedName, t.Namespace but none produce the desired results.
I did come up with a solution that works using the custom naming strategy but it looks horrible and is super hacky:
c.SchemaId(t => t.FullName.Contains("System.Collections.Generic.List") ?
"ODataResponse[List[" +
t.FullName.Substring(t.FullName.IndexOf("MyProject.") + 10, (t.FullName.IndexOf(",") - 10 - t.FullName.IndexOf("MyProject.")))
+ "]]"
: (t.FullName.Contains("Microsoft.Spatial.CoordinateSystem") ? t.FullName : t.Name));
Does this seem to be a bug within Swagger/Swashbuckle or am I doing something wrong with the c.SchemaId code?

StructureMap error - no default instance is registered

I have a console demo app using StructureMap IoC container. The demo has all the interfaces and implementation all in one file in one project and the scanning registry looks like the following:
public class ConsoleRegistry : Registry
{
public ConsoleRegistry()
{
Scan(scan =>
{
scan.TheCallingAssembly();
scan.WithDefaultConventions();
});
}
}
And the demo uses the convention ISomething and Something so StructureMap can automatically find an implementation for an interface.
Now, when I go to move this to a real project where there is a UI project and Business project. I keep the convention of ISomething and Something but I get the following error message when I try to run an integration test in my unit test project.
Message: Test method
AbcCompany.Tests.IntegrationTestsForTasks.Get_something_test threw
exception: StructureMap.StructureMapConfigurationException: No
default Instance is registered and cannot be automatically determined
for type 'AbcCompany.DomainLayer.ISomething'
There is no configuration specified for
AbcCompany.DomainLayer.ISomething
1.) Container.GetInstance()
If I change the registry to the following it works:
class ScanningRegistry : Registry
{
public ScanningRegistry()
{
this.For<ISomething>().Use<Something>();
this.Policies.SetAllProperties(y => y.WithAnyTypeFromNamespaceContainingType<Something>());
}
}
However, I like that if I stay with standard naming convention StructureMap will find all my interfaces and implementation for me without having to specify them.
You are only scanning TheCallingAssembly. When your application runs, the calling assembly is your application. When the test runner runs, the calling assembly is the test runner.
To make it reliable, you should manually specify each assembly:
Scan(scan =>
{
scan.Assembly(typeof(SomeTypeFromAssembly1).Assembly);
scan.Assembly(typeof(SomeTypeFromAssembly2).Assembly);
scan.WithDefaultConventions();
});
Or you should use one of the other methods in the scanning documentation to specify assemblies by directory name.

Categories

Resources