BLAZOR server side - use ProtectedSessionStorage in a class - visual-studio-2019

I have implemented the access to keys through SessionStorage, if I do it from a Razor component, I inject the dependency and in the code I access it without problems.
The problem is when I want to read a key but through a method in a class
Example
public class FuncionesVarias
{
[Inject]
public ProtectedSessionStorage SessionStorage { get; set; }
public async Task LeoSessionStorage()
{
var miSingleton = MiSingleton.Instancia;
var result = await SessionStorage.GetAsync<string>("SS");
miSingleton.ValorEnSesion = result.Success ? result.Value : string.Empty;
}
}
That does NOT work, in the line where I do the GetAsync it gives me this error:
System.NullReferenceException: 'Object reference not set to an instance of an object.'
thanks for your help

Related

Blazor WebAssembly: using Constructor injection for injecting Blazored.LocalStorage into a service

The package Blazored.LocalStorage is:
a library to provide access to local storage in Blazor applications
Injecting the service into a component is easy:
#inject Blazored.LocalStorage.ILocalStorageService localStorage
and if we want to inject it into the code behind:
[Inject]
private ILocalStorageService localStorage { get; set; }
But suppose I want to inject it into another service (let say for centralizing the control):
public class StorageManagement
{
public StorageManagement(LocalStorageService localStorage)
{
//How to initialize it here?
}
}
I do not know how to initialize an instance of the service in the constructor of StorageManagement and also how to set the parameters of constructor of StorageManagement in Program.cs :
builder.Services.AddSingleton(e => new StorageManagement(//?));
Just builder.Services.AddBlazoredLocalStorage(); or builder.Services.AddBlazoredLocalStorage(config => config.JsonSerializerOptions.WriteIndented = true); as it's explain in README.
Then builder.Services.AddScoped<StorageManagement>(); or builder.Services.AddScoped(p => new StorageManagement(p.GetRequiredSerice<ILocalStorageService>()));
But your service should take a ILocalStorageService not a LocalStorageService instance :
public class StorageManagement
{
public StorageManagement(ILocalStorageService localStorage)
{
//How to initialize it here?
}
}
You are not using the Interface ILocalStorageServer in your constructor, it should be
public class StorageManagement
{
private readonly ILocalStorageService LocalStorage;
public StorageManagement(ILocalStorageService localStorage)
{
LocalStorage = localStorage;
}
}

Resolving dependencies in a reference assembly in a .net core console application

I'm testing a small console application which will be used to display information based on a Quartz queue and I'm struggling to the the dependency to resolve within a reference assembly.
My console application references an EventData class, which has a dependency on IUtilities, within an assembly called App.Monitor, it's partial'ed as the base is code generated, and we're adding these properties / methods to the class for specific reasons...
public partial class EventData
{
private readonly IUtilities _utilities;
[JsonIgnore]
public DateTime? DateStamp => _utilities?.Epoch(Timestamp);
[JsonIgnore]
public EventType EventType =>
(EventType)EventType.Parse(typeof(EventType), (CultureInfo.CurrentCulture.TextInfo.ToTitleCase(Event)));
public EventData(IUtilities utitlies)
{
_utilities = utitlies;
}
}
In my console application I set up .net core dependency injection per various examples on the net, code for reference:
public IServiceProvider BuildDependencies()
{
services.AddTransient<IHttpContextAccessor, HttpContextAccessor>();
services.AddTransient<IUtilities, Utilities>();
return services.BuildServiceProvider();
}
Then somewhere in the console application, I'm doing a call that should initiate this dependency in utilities, which it doesn't do, IUtilities is always NULL:
provider.GetRequiredService<IUtilities>(); // thought this would fix it...
var list = JsonConvert.DeserializeObject<List<QuartzJobs>>(json);
var stamp = list[0].EventData.DateStamp;
Update
QuartzJobs (code generated)
public class QuartzJobs
{
[JsonProperty("event-data")]
public EventData EventData { get; set; }
}
EventData (code generated)
public partial class EventData
{
[JsonProperty("timestamp")]
public double Timestamp { get; set; }
}
EventData (partial'ed with custom logic)
public partial class EventData
{
private readonly IUtilities _utilities;
[JsonIgnore]
public DateTime? DateStamp => _utilities?.Epoch(Timestamp);
[JsonIgnore]
public EventType EventType =>
(EventType)EventType.Parse(typeof(EventType), (CultureInfo.CurrentCulture.TextInfo.ToTitleCase(Event)));
public EventData(IUtilities utitlies)
{
_utilities = utitlies;
}
}
In the console you would need to take over the role of the framework and get the dependency and call the desired member
var utility = provider.GetRequiredService<IUtilities>();
var list = JsonConvert.DeserializeObject<List<QuartzJobs>>(json);
var stamp = utility?.Epoch(list[0].EventData.Timestamp);
That is because the container/provider is not the one resolving the EventData, so nothing is being injected.

OptionsModel dependency injection in vNext console application

I have a vNext console application where one of my classes takes the OptionsModel<T> POCO configuration settings class.
I am unable to get the POCO settings class resolved and injected into my RabbitMqConnection class below.
Setting up the ServiceProvider is not the issue, it's the resolution of the settings class.
Note, this is a vNext console application (not an mvc6 app).
My second question is, and I understand constructor arguments should be kept minimal, but is it not best to pass the two strings as constructor arguments rather than an IOptions class as the former method is more descriptive of what the RabbitMqConnection class requires? If so, how is this best injected from the class that defined the mappings (Program.cs file in example below)
public class RabbitMqConnection
{
public string HostName { get; set; }
public string UserName { get; set; }
public RabbitMqConnection(IOptions<MessagingSettings> settings)
{
HostName = settings.Value.HostName;
UserName = settings.Value.UserName;
}
}
public class MessagingSettings
{
public string HostName { get; set; }
public string UserName { get; set; }
}
appsettings.json
{
"MessagingSettings":{
"HostName":"localhost",
"Username":"guest"
}
}
public void ConfigureServices(IServiceCollection services)
{
// tried registration a number of ways as below
services.Configure<MessagingSettings>(Configuration.GetSection("MessagingSettings"));
services.Configure<MessagingSettings>(Configuration);
// attempt 1 - get runtime error saying cant resolve IOptions<MessageSettings>
services.TryAdd(ServiceDescriptor.Singleton<RabbitMqConnection, RabbitMqConnection>());
// attempt 2 - same as above, when i breakpoint on messagingSettings, all the values in the object are null
services.TryAdd(ServiceDescriptor.Singleton<RabbitMqConnection>(factory =>
{
// instead of injecting the MessageSettings, pass through the string values (constructor omitted for clarity)
var messagingSettings = Configuration.Get<MessagingSettings>();
return new RabbitMqConnection(messagingSettings.HostName, messagingSettings.UserName);
}));
}
var conn = ServiceProvider.GetRequiredService<RabbitMqConnection>();
You need to call services.AddOptions()

Ninject - how and when to inject

I'm a newbie when it comes to DI and ninject and I'm struggling a bit
about when the actual injection should happen and how to start the
binding.
I'm using it already in my web application and it working fine there,
but now I want to use injection in a class library.
Say I have a class like this:
public class TestClass
{
[Inject]
public IRoleRepository RoleRepository { get; set; }
[Inject]
public ISiteRepository SiteRepository { get; set; }
[Inject]
public IUserRepository UserRepository { get; set; }
private readonly string _fileName;
public TestClass(string fileName)
{
_fileName = fileName;
}
public void ImportData()
{
var user = UserRepository.GetByUserName("myname");
var role = RoleRepository.GetByRoleName("myname");
var site = SiteRepository.GetByID(15);
// Use file etc
}
}
I want to use property injection here because I need to pass in a
filename in my constructor. Am I correct in saying that if I need to
pass in a constructor parameter, I cannot use constructor injection?
If I can use constructor injection with additional parameters, how do
I pass those parameters in?
I have a console app that consumes by Test class that looks as
follows:
class Program
{
static void Main(string[] args)
{
// NinjectRepositoryModule Binds my IRoleRepository etc to concrete
// types and works fine as I'm using it in my web app without any
// problems
IKernel kernel = new StandardKernel(new NinjectRepositoryModule());
var test = new TestClass("filename");
test.ImportData();
}
}
My problem is that when I call test.ImportData() my repositories are null - nothing has been injected into them. I have tried creating another module and calling
Bind<TestClass>().ToSelf();
as I thought this might resolve all injection properties in TestClass but I'm getting nowhere.
I'm sure this is a trivial problem, but I just can't seem to find out
how to go about this.
You are directly newing TestClass, which Ninject has no way of intercepting - remember there's no magic like code transformation intercepting your news etc.
You should be doing kernel.Get<TestClass> instead.
Failing that, you can inject it after you new it with a kernel.Inject( test);
I think there's an article in the wiki that talks about Inject vs Get etc.
Note that in general, direct Get or Inject calls are a Doing It Wrong smell of Service Location, which is an antipattern. In the case of your web app, the NinjectHttpModule and PageBase are the hook that intercepts object creation - there are similar interceptors / logical places to intercept in other styles of app.
Re your Bind<TestClass>().ToSelf(), generally a StandardKernel has ImplicitSelfBinding = true which would make that unnecessary (unless you want to influence its Scope to be something other than .InTransientScope()).
A final style point:- you're using property injection. There are rarely good reasons for this, so you should be using constructor injection instead.
And do go buy Dependency Injection in .NET by #Mark Seemann, who has stacks of excellent posts around here which cover lots of important but subtle considerations in and around the Dependency Injection area.
OK,
I've found out how to do what I need, thanks in part to your comments Ruben. I've created a new module that basically holds the configuration that I use in the class library. Within this module I can either Bind using a placeholder Interface or I can add a constructor parameter to the CustomerLoader.
Below is the code from a dummy console app to demonstrating both ways.
This might help someone else getting started with Ninject!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Ninject.Core;
using Ninject.Core.Behavior;
namespace NinjectTest
{
public class Program
{
public static void Main(string[] args)
{
var kernel = new StandardKernel(new RepositoryModule(), new ProgramModule());
var loader = kernel.Get<CustomerLoader>();
loader.LoadCustomer();
Console.ReadKey();
}
}
public class ProgramModule : StandardModule
{
public override void Load()
{
// To get ninject to add the constructor parameter uncomment the line below
//Bind<CustomerLoader>().ToSelf().WithArgument("fileName", "string argument file name");
Bind<LiveFileName>().To<LiveFileName>();
}
}
public class RepositoryModule : StandardModule
{
public override void Load()
{
Bind<ICustomerRepository>().To<CustomerRepository>().Using<SingletonBehavior>();
}
}
public interface IFileNameContainer
{
string FileName { get; }
}
public class LiveFileName : IFileNameContainer
{
public string FileName
{
get { return "live file name"; }
}
}
public class CustomerLoader
{
[Inject]
public ICustomerRepository CustomerRepository { get; set; }
private string _fileName;
// To get ninject to add the constructor parameter uncomment the line below
//public CustomerLoader(string fileName)
//{
// _fileName = fileName;
//}
public CustomerLoader(IFileNameContainer fileNameContainer)
{
_fileName = fileNameContainer.FileName;
}
public void LoadCustomer()
{
Customer c = CustomerRepository.GetCustomer();
Console.WriteLine(string.Format("Name:{0}\nAge:{1}\nFile name is:{2}", c.Name, c.Age, _fileName));
}
}
public interface ICustomerRepository
{
Customer GetCustomer();
}
public class CustomerRepository : ICustomerRepository
{
public Customer GetCustomer()
{
return new Customer() { Name = "Ciaran", Age = 29 };
}
}
public class Customer
{
public string Name { get; set; }
public int Age { get; set; }
}
}

ASP.NET MVC - Ninject 2.0 Activation Error

I just started working with dependency injection for the first time and I am using as Ninject 2.0 as my IoC container in an ASP.NET MVC 2 website and I'm hitting an activation error that I am not sure how to react to. I am sure it's simple so hopefully someone can point me in the right direction without too much thought.
I have a property on my class BaseController which takes an IWebsiteSettings and is flagged with the [Inject] attribute. In my StandardKernel I load a module with the following code:
public class WebModule : Module
{
public override void Load()
{
Bind<IWebsiteSettings>()
.ToProvider(new WebsiteSettingsProvider(WebConfigurationManager.AppSettings))
.InSingletonScope();
}
}
public class WebsiteSettingsProvider : Provider<WebsiteSettings>
{
private const string WebsiteNameKey = "Website.Name";
private const string ContactFormEmailSubjectKey = "ContactForm.EmailSubject";
private const string ProductImageDirectoryKey = "Products.ImageDirectory";
private const string UploadTempDirectoryKey = "Uploads.TempDirectory";
protected NameValueCollection Settings { get; set; }
public WebsiteSettingsProvider(NameValueCollection settings)
{
Settings = settings;
}
protected override WebsiteSettings CreateInstance(IContext context)
{
return new WebsiteSettings
{
WebsiteName = Settings[WebsiteNameKey] ?? string.Empty,
ContactFormEmailSubject = Settings[ContactFormEmailSubjectKey] ?? string.Empty,
ProductImageDirectory = Settings[ProductImageDirectoryKey] ?? string.Empty,
UploadsTemporaryDirectory = Settings[UploadTempDirectoryKey] ?? string.Empty
};
}
}
This is fairly straightforward- I'm trying to load some data from the web.config file and store it in a singleton object for use across my controllers. The call to Bind seems to function exactly as it should and the Settings property in my provider is correctly initialized with the AppSettings collection in the config file. Still, when the application loads the first time:
Server Error in '/' Application.
Error activating SByte* using implicit self-binding of SByte*
No constructor was available to create an instance of the implementation type.
Activation path:
4) Injection of dependency SByte* into parameter value of constructor of type string
3) Injection of dependency string into property WebsiteName of type WebsiteSettings
2) Injection of dependency IWebsiteSettings into property WebsiteSettings of type HomeController
1) Request for HomeController
Suggestions:
1) Ensure that the implementation type has a public constructor.
2) If you have implemented the Singleton pattern, use a binding with InSingletonScope() instead.
Interestingly, if I refresh the page I don't get the exception and a call to Kernel.Get() returns the correct object.
Any advice?
(We talked about this on IRC, but I'm putting it here in case someone else runs into this problem as well.)
WebsiteSettings has [Inject] attributes on its properties, so Ninject is trying to resolve a binding from System.String to inject a value into the properties. Since you're using a custom provider to activate WebsiteSettings instances, you don't need [Inject] attributes on its properties.
The offending code was actually in the class WebsiteSettings where I was doing this:
public class WebsiteSettings : IWebsiteSettings
{
[Ninject.Inject]
public string WebsiteName
{
get; set;
}
[Ninject.Inject]
public string UploadsTemporaryDirectory
{
get; set;
}
[Ninject.Inject]
public string ContactFormEmailSubject
{
get; set;
}
[Ninject.Inject]
public string ProductImageDirectory
{
get; set;
}
}
By placing the Inject attribute on my properties I was causing Ninject to try to assign values that I never bound. Because I am using a Provider to load my type I do not need to include the Inject attribute.

Resources