Initialize Singleton variable in Startup and use it in wole app - dependency-injection

I want to store data in an object and I want to use this in the whole app. I created an Object and register as Singleton in Program.cs
Object:
private Dictionary<string, string> _currentValues;
public Dictionary<string, string> currentValues
{
get => _currentValues;
set
{
_currentValues = value;
StateHasChanged();
}
}
Singleton Registration:
services.AddSingleton<LocalizeData>();
In program.cs after registration I added initial data.
var _localizeData = host.Services.GetRequiredService<LocalizeData>();
_localizeData.currentValues = locaData;
Now I want to use these data in the whole app. I injected it main Page.
#LocalizeData localizeData
If I use now localizeData.currentValues the object is null.
What is missing. How can I initialize an object in Starttup and how can I use the data in whole app?

You're almost there. :D
To use services in your component, you need to use the inject keyword:
#inject LocalizeData localizeData

The Problem was I used
await builder.Build().RunAsync();
instead of
await host.RunAsync();
This was the reason why I created a second instance and I could not access my initialize data.
See documentation:
https://learn.microsoft.com/en-us/aspnet/core/blazor/fundamentals/dependency-injection?view=aspnetcore-5.0&pivots=webassembly

Related

Accessing metadata from NestJS controllers

is there a way to access metadata from controller methods?
For example, I add metadata to a controller class with SetMetadata() - e.g. from a decorator.
I know how to access metadata in a guard. You need to inject reflector and guard.canActivate() has ExecutionContext parameter.
canActivate(context: ExecutionContext): boolean {
metadata: SomeType = this.reflector.get<EnabledFeatures>(SOME_METADATA_KEY, [context.getClass()]);
}
To get metadata I need 2 components: Reflector and ExecutionContext.
I can inject Reflector into controller, but how can I access ExecutionContext from a controller?
Assuming we set some metadata on Controller with #SetMetadata :
#Controller({...})
#SetMetadata('roles', ['admin'])
We can have access to it, by creating our custom param decorator:
export const Roles = createParamDecorator(
(data: unknown, ctx: ExecutionContext) => {
// get roles metadata from #Controller class
const roles = Reflect.getMetadata('roles', ctx.getClass());
return roles;
},
);
And then we can use it on controller's method :
#Get()
getInfo(#Roles() roles): string {
// roles = ['admin']
//...
}
Some notes
#SetMetadata not a good practice
Usage of #SetMetadata directly is not really a good practice. Prefer to create a specific decorator (for maintenance and readability of code) :
export const SetRoles = (...roles: string[]) => SetMetadata('roles', roles);
...
#Controller({...})
#SetRoles('admin')
export class MyController {...}
Reflect.getMetadata API vs Injector
Even if Reflect.getMetadata is in fact called by Reflector API of NestJS, it could be changed in the future.
So if we want to deal with only public/documented API of NestJS, we can:
use a global guard, which will inject Injector,
get metadata with ExecutionContext
and then set result in Request instance.
An other custom param decorator will retrieve data from Request and return it.
More complicated, but without using direct call to Reflect.getMetadata API.

how to get an unsaved entity on server but not for saving?

i need to send my unsaved entity from the client to the server but not for saving changes
but inorder to do a process using the data on the entity and then change some of it's values and pass it back to the client
is this possible?
if not what are my options?
i tried to export the entity and then send it to a method on the webapi controller that gets a JObject but didn't find a way to deserialize it to the server entity
We did have a similar problem and found a solution as follows:
You need to take into consideration the way breeze manages it's objects.
1.Create custom saveBundle.
Consider complex order object.You need to fill your save bundle with each nested object inside order.
Like:
var saveBundle = new Array();
saveBundle.push(order.SaleAccountingInfo);
saveBundle.push(order.CostAccountingInfo);
saveBundle.push(order);
2.Create custom save options, where you can point to your custom Save Method on server
Like:
var so = new breeze.SaveOptions({ resourceName: "BookOrder" });
3.Call standard breeze function and pass it created params
manager.saveChanges(saveBundle, so).fail(function () {
// manager.rejectChanges();TODO check what needed
deferred.resolve(true);
});
On server you need to have you custom function ready and hook some breeze delegates
[HttpPost]
public SaveResult BookOrder(JObject orderBundle)
{
context.BeforeSaveEntityDelegate = OrderBeforeSaveEntity;
context.BeforeSaveEntitiesDelegate = SaveOrder;
context.AfterSaveEntitiesDelegate = BookOrderAfterSave;
try
{
return context.SaveChanges(orderBundle);
}
catch (Exception)
{
throw;
}
}
You can a lot of stuff in first two delegates but it is the last one you are looking for
private void BookOrderAfterSave(Dictionary<Type, List<EntityInfo>> orderSaveMap, List<KeyMapping> orderKeyMappings)
{
var orderEntity = orderSaveMap.Where(c => c.Key == typeof(BL.Orders.Order)).Select(d => d.Value).SingleOrDefault();
BL.Orders.Order order = (BL.Orders.Order)orderEntity[0].Entity; //your entity
//logic here
}
Hope it points to right direction.
we are doing something similar here. it'll save the entity so i'm not sure if this fits your question.
you can do:
entity.entityAspect.setModified()
then issue a saveChange()
then you can do your calculations on the server.
in our case we are using breeze.webapi so we are doing this in the beforeSave(entity) method.
breeze by design sends the changed entity then back to the client where the cache gets updated with your changes done on the server.

How to initialize and persist Castle ActiveRecordStarter per session for multi tenancy apps?

I am using Castle ActiveRecord in my Asp.net / MVC 2 / Multi-tenancy application with SQL Server as my backend.
For every user logging in, the app loads the corresponding DB, dynamically at run time like below:
IDictionary<string, string> properties = new Dictionary<string, string>();
properties.Add("connection.driver_class", "NHibernate.Driver.SqlClientDriver");
properties.Add("dialect", "NHibernate.Dialect.MsSql2005Dialect");
properties.Add("connection.provider", "NHibernate.Connection.DriverConnectionProvider");
properties.Add("proxyfactory.factory_class", "NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle");
properties.Add("connection.connection_string", strDBConnection);
InPlaceConfigurationSource source = new InPlaceConfigurationSource();
source.Add(typeof(ActiveRecordBase), properties);
ActiveRecordStarter.Initialize(new System.Reflection.Assembly[] { asm1 }, source);
The strDBConnection string comes from another small database that holds the user info, corresponding DB, etc.
Scenario:
When a user logs in, his DB gets loaded, he can do his CRUD jobs -- No Probs !
Another user logs in (from another remote machine) his DB gets loaded -- No Probs !
Now, when the first user reads from DB, he sees new data from the second user's DB
My little understanding for this behavious is : ActiveRecordStarter is a Static object.
Could someone help me with a solution for this situation ?
The expected behaviour:
each user should access his own DB only, securely, in parallel / at the same time.
Thanks a lot !
ActiveRecordStarter.Initialize should only be called once in your app (in Application_Start in Global.asax).
To achieve what you want, create a class that inherits from NHibernate.Connection.DriverConnectionProvider:
public class MyCustomConnectionProvider : DriverConnectionProvider
{
protected override string GetNamedConnectionString(IDictionary<string, string> settings)
{
return string.Empty;
}
public override IDbConnection GetConnection()
{
// Get your connection here, based on the request
// You can use HttpContext.Current to get information about the current request
var conn = Driver.CreateConnection();
conn.ConnectionString = ... // Retrieve the connection string here;
conn.Open();
return conn;
}
}
Then set the connection.provider property to the name of your class:
properties.Add("connection.provider", "MyCompany.Domain.MyCustomConnectionProvider, MyCompany.AssemblyName");

ASP.NET MVC 4 Unit Test - Is there a way to mock HttpClientCertificate with Moq

My web app is using PKI authentication via a piv card. I grab the user's unique identifier information via HttpClientCertificate.Subject. The problem is that when I am unit testing, mock will not mock this class since it doesn't have a constructor. I tried following the advice on this thread:
How to mock HttpClientCertificate?
but it looks like the way he sets it up is to inject the client certificate through the controller's constructor which I dont' want to do since the controller already has access to the client certificate. I'm assuming thats what he is implying since he is using some type of adapter pattern. Anyone got any better sugguestions?
Why don't you wrap it into your own object?
class MyHttpClientCertificate
{
public MyHttpClientCertificate(HttpClientCertificate foo) { ... }
internal MyHttpClientCertificate() { ... }
}
Your issue is that the code is using the Request object to get the certificate, but that's not easily unit testable.
What I would do is add a function delegate that, by default, will use the Request object to return the HttpClientCertificate, but will allow overriding the implementation.
For the controller, add this:
internal Func<HttpClientCertificate> HttpClientCertificateGetter = () => {
return Request.ClientCertificate;
}
And in your Controller instead of using Request use HttpClientCertificateGetter.
Then in your unit test you mock the certificate and assign it to the getter function, like this:
var certMock = new Mock<HttpClientCertificate>();
HttpClientCertificate clientCertificate = certMock.Object;
requestMock.Setup(b => b.ClientCertificate).Returns(clientCertificate);
certMock.Setup(b => b.Certificate).Returns(new Byte[] { });
controller.HttpClientCertificateGetter = () => {certMock.Object};

Using Ninject.MockingKernel with Asp.Net Web API

I've set up a Web API project using Ninject, and I've used the fix detailed here for getting it to work with the latest version of the Web API. Everything is working fine, but I'm now trying to write some tests.
I'm using in-memory hosting to run the project for the tests, as detailed here, as I have a DelegatingHandler that performs authentication and then sets a property on the request message that is used by all the Api Controllers.
So, I've got a base class for my tests, and have a SetUp method where I set up the HttpServer and configuration, which I've pretty much taken from my working Ninject code:
[SetUp]
public void Setup()
{
bootstrapper = new Bootstrapper();
DynamicModuleUtility.RegisterModule(
typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(
typeof(NinjectHttpModule));
bootstrapper.Initialize(CreateKernel);
var config = new HttpConfiguration();
config.Routes.MapHttpRoute("Login",
"api/auth/token",
new { controller = "Users", action = "Login" });
config.IncludeErrorDetailPolicy =
IncludeErrorDetailPolicy.Always;
config.DependencyResolver =
new NinjectResolver(CreateKernel());
config.MessageHandlers.Add(
new AuthenticationHandler(CreateUserManager()));
Server = new HttpServer(config);
}
This is how I create the MoqMockingKernel:
private static IKernel CreateKernel()
{
var kernel = new MoqMockingKernel();
kernel.Bind<Func<IKernel>>()
.ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>()
.To<HttpApplicationInitializationHttpModule>();
RegisterServices(kernel);
GlobalConfiguration.Configuration.DependencyResolver =
new NinjectResolver(kernel);
return kernel;
}
And this is how I register the objects to use:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IUserManager>().ToMock();
kernel.Bind<UsersController>().ToSelf();
}
While I'm not testing the Controller per se, I do want a proper instance of it to be called, which is why I'm binding it ToSelf. I must admit that I am assuming that this is correct. This is an example of a test:
public void UserCannotLogin()
{
System.Net.Http.HttpClient client =
new System.Net.Http.HttpClient(Server);
string json = string.Format(
"{{ \"Username\": \"{0}\", \"Password\": \"{1}\" }}",
"wrong", "wrong");
HttpRequestMessage request =
CreateRequest(#"api/auth/token", json, HttpMethod.Get);
Action action = () => client.SendAsync(request);
using (var response = client.SendAsync(request).Result)
{
response.StatusCode.Should()
.Be(HttpStatusCode.Unauthorized);
}
}
I'm basically getting a 404 error. When I debug it, it does go to my DelegatingHandler, but it doesn't go to my controller.
I get the feeling that I'm fundamentally missing a point here, and it may not even be possible to do what I'm trying to do, but if anyone has any suggestions for either how to do this, or a different way to achieve the same thing, I'm all ears.
Update I think that it's because the default behaviour of the MockingKernel is to provide a Mock unless told otherwise, so it is returning a Mock of IHttpControllerSelector. I've set up a couple of default ones now:
kernel.Bind<IHttpControllerSelector>()
.To<DefaultHttpControllerSelector>();
kernel.Bind<IContentNegotiator>()
.To<DefaultContentNegotiator>();
It's still not working, I think because there are no formatters specified. I'll try that tomorrow and see if that gets me there.
Ok, I think that I was correct when I said that I was fundamentally missing a point here, but I'll answer this in case it helps someone else avoid the same mistake!
The Ninject MockingKernel is, I think, primarily about auto-mocking, so where you have a lot of interfaces you don't care about how they are set up in your test, you can ignore them in your tests and they will be automatically created for you.
In the case of the Web API, this is most definitely not the case, as you don't want the controller selector class to be auto mocked, otherwise you won't end up calling your controllers.
So, the solution I've come up with is to stick with using a standard Ninject Kernel, and then bind your interface to a constant Mock object:
kernel.Bind<IUserManager>().ToConstant(CreateUserManager());
private IUserManager CreateUserManager()
{
Mock<IUserManager> userManager = new Mock<IUserManager>();
// Set up the methods you want mocked
return userManager.Object;
}
Doing this, I've been able to successfully write tests that use an HttpClient to call an in-memory HttpServer that successfully call my DelegatingHandler and then end up at my controllers.

Resources