Update:
Vote to close this please, my mistake where I was assigning the Authorisation I wasn't assigning it to the instance.
I'm having an issue with the following code, basically I have two classes which are singletons within, they are declared at the top of my "MainWindow":
public partial class MainWindow : MetroWindow
{
public Auth AuthInfo = Auth.GetInstance();
public api myApi = api.GetInstance();
The line that sets it a bit further down within the MainWindow class, if I debug this after the assignment the Authorisation string is set.
AuthInfo = JsonConvert.DeserializeObject<Auth>(responseString);
The class declarations are as follows:
Auth
public class Auth
{
private static Auth instance = new Auth();
private Auth(){}
public static Auth GetInstance()
{
return instance;
}
public string Authorisation { get; set; }
}
api
public class api
{
private static api instance = new api();
Auth AuthInfo = Auth.GetInstance();
private api(){}
public static api GetInstance()
{
return instance;
}
// other code goes here
}
The problem is when I try and access the Authorisation property of the Auth instance from within the api class it's not set? It's almost like GetInstance returns the instance without any properties?
From within the MainWindow class the authorisation property is correct
Try this:
public class Auth
{
private static Auth instance = new Auth();
private Auth(){}
public static Auth GetInstance()
{
if (instance == null) \\ADDED
instance = new Auth();
return instance;
}
public string Authorisation { get; set; }
}
Instantiate in the static method itself:
public class Auth
{
private static Auth instance;
private Auth(){}
public static Auth GetInstance()
{
if (instance == null)
instance = new Auth();
return instance;
}
public string Authorisation { get; set; }
}
Related
i need to access my enviroment variables from a singleton class.
I only found soulutions where the WebBuilder injects the configuration through the constructor or methods to a PageModel.
Singleton Class
public class GraphQLAPI
{
public static GraphQLAPI Instance {
get
{
if (_instance == null)
_instance = new GraphQLAPI();
return _instance;
}
}
private static GraphQLAPI _instance;
private GraphQLAPI()
{
_qlClient = new GraphQLHttpClient("XXX", new SystemTextJsonSerializer());
_qlClient.HttpClient.DefaultRequestHeaders.Add("Authorization", "XXX");
}
[...]
}
Is it even possible? If not, is there another way to pass the value to my client?
I just created 2 static fields in the GraphQLAPI.cs which will be set in the Startup.cs
GraphQLAPI.cs
public class GraphQLAPI
{
public static string GraphQLHostUrl { get; set; }
public static string GraphQLAuthorization { get; set; }
[...]
private GraphQLAPI()
{
_qlClient = new GraphQLHttpClient(GraphQLHostUrl, new SystemTextJsonSerializer());
_qlClient.HttpClient.DefaultRequestHeaders.Add("Authorization", GraphQLAuthorization);
}
[...]
}
Startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
GraphQLAPI.GraphQLHostUrl = configuration.GetValue<string>("GraphQlUrl");
GraphQLAPI.GraphQLAuthorization = configuration.GetValue<string>("ApiAuthorization");
}
[...]
}
Is there a way the tell the ActivatorUtilities.CreateInstance<T>(IServiceProvider serviceProvider); method to try to use other constructors if the first one can't be constructed?
I have a class with multiple constructors:
public ViewModelB(SomeDependency someDependency): this one only takes SomeDependency which is registered in a DI container
public ViewModelB(SomeDependency someDependency, GetUserRequest request): this one takes SomeDependency which is registered in a DI container and a GetUserRequest which has to be passed in manually
And I'm trying to activate them and resolve dependencies like so:
IServiceProvider serviceProvider; //this gets passed from somewhere
Guid userId; //this gets passed manually by the caller
//works
var instanceAWithoutParams = ActivatorUtilities.CreateInstance<ViewModelA>(serviceProvider);
//works
var instanceAWithParams = ActivatorUtilities.CreateInstance<ViewModelA>(serviceProvider, new[] { new GetUserRequest { UserId = userId } });
//does NOT work, it tries to use the first constructor and fails
var instanceBWithoutParams = ActivatorUtilities.CreateInstance<ViewModelB>(serviceProvider);
//works
var instanceBWithParams = ActivatorUtilities.CreateInstance<ViewModelB>(serviceProvider,, new[] { new GetUserRequest { UserId = userId } });
The activation of instanceBWithoutParams fails because it can't resolve the request parameter. It tries to use the first constructor and doesn't check other ones when the activation fails.
Here's what the services look like, they're the same with one difference: the order of the constructors.
public class ViewModelA
{
private readonly SomeDependency _someDependency;
private readonly GetUserRequest? _request;
public ViewModelA(SomeDependency someDependency)
{
_someDependency = someDependency;
}
public ViewModelA(SomeDependency someDependency, GetUserRequest request)
{
_someDependency = someDependency;
_request = request;
}
}
public class ViewModelB
{
private readonly SomeDependency _someDependency;
private readonly GetUserRequest? _request;
public ViewModelB(SomeDependency someDependency, GetUserRequest request)
{
_someDependency = someDependency;
_request = request;
}
public ViewModelB(SomeDependency someDependency)
{
_someDependency = someDependency;
}
}
public class GetUserRequest
{
public Guid UserId { get; set; }
}
Thanks.
I struggled with the same issue. Eventually I came up with this solution:
I would use something like a factory which is able to construct ServiceB by calling a method.
For example:
var serviceBFactory = ActivatorUtilities.CreateInstance<ServiceBFactory>(serviceProvider);
var instanceBWithoutParams = serviceBFactory.CreateServiceB();
var instanceBWithParams = serviceBFactory.CreateServiceB(new Request());
This way you keep you DI clean. But this means that the ServiceBFactory need to know which services need to be injected in a ServiceB. (so that will be a tight coupling) They come as a package.
I've chosen to re-design the view models instead of trying to pass optional parameters next to services from DI (thanks to Steven for the helpful articles: 1 and 2).
There also seems to be no way of making the ActivatorUtilities.CreateInstance<T>(IServiceProvider serviceProvider); method try other constructors after one fails, so here's what my edited solution looks like.
I've moved the initialization of the optional parameter out of the constructor, that way I only have one constructor that only takes injectables. The parameter is then passed separately via the TakeParameter method. The only downside I can think of is that the parameter can no longer be readonly and I can live with that.
My custom activator utility:
public interface IAcceptParameter<T>
{
void TakeParameter(T parameter);
}
public static class CustomActivator
{
public static T CreateInstance<T>()
{
return ActivatorUtilities.CreateInstance<T>(_serviceProvider);
}
public static T CreateInstanceWithParam<T, K>(K parameter) where T : IAcceptParameter<K>
{
var instance = ActivatorUtilities.CreateInstance<T>(_serviceProvider);
instance.TakeParameter(parameter);
return instance;
}
}
Changed view model
public class SomeViewModel : IAcceptParameter<Guid>
{
private readonly SomeDependency _someDependency;
private Guid? _userId;
public SomeViewModel(SomeDependency someDependency)
{
_someDependency = someDependency;
}
public void TakeParameter(Guid parameter){
_userId = parameter;
}
}
How I use it
var instanceWithoutParam = CustomActivator.CreateInstance<SomeViewModel>(serviceProvider);
Guid userId;
var instanceWithParam = CustomActivator.CreateInstanceWithParam<SomeViewModel, Guid>(serviceProvider, userId);
Let say you have a class like this:
public class a
{
public string p { get; set; }
public a()
{
p = "default constructor";
}
public a(string pv)
{
p = pv;
}
}
You can use .GetConstructor method to use a specific constructor:
public class Program
{
static void Main(string[] args)
{
var c = typeof(a).GetConstructor(new Type[] { typeof(string) });
if (c != null)
{
var myA = (a)c.Invoke(new object[] { "new value" });
Console.WriteLine($"Value of p is {myA.p}");
}
}
}
I am designing a program with AOP architecture(postsharp) that will intercept all method calls but I need a way to attach a class to every call. The problem is I don't want to have to pass the class explicitly in every single method call. So is there a way to attach a class to a method call in C#?
For example, In angular I can use a custom interceptor to attach anything I want to a header for every outgoing call. This saves down on repeating code. Is there anything like this in C#?
#Injectable()
export class CustomInterceptor implements HttpInterceptor {
constructor() { }
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
request = request.clone({ withCredentials: true });
return next.handle(request);
}
}
This is my interface in C#
public class Wrapper: IMyInterface
{
private IMyInterface_wrapped;
public Wrapper(IMyInterface caller)
{
_wrapped = caller;
}
public FOO GetUserStuff(string userName)
{
return _wrapped.GetUserStuff(req);
}
}
}
Is there a way that I can call the interface like this
var wrapper = new Wrapper(new MyInterface());
LoginRequest req = new LoginRequest <------ this needs to be attached to every single method call
{
ClientId = "ABCDEFG",
ClientSecret = "123456"
};
wrapper.GetUserStuff("Username", req); <------- My interface only takes one argument.
wrapper.GetUserStuff("UserName").append(req) <----of course this doesn't work either
Is there a way that I can call the interface method and attach the object to it without actually implementing it in the interface?
Basically what you want is - whenever the wrapper.GetUserStuff method gets called, a LoginRequest object be available to the Wrapper class object.
But as you answered in the comment section, the value for ClientId and ClientSecret don't change. Then you can avoid the whole hassle of creating the LoginRequest object outside each time and passing it inside as a method parameter by simply creating the LoginRequest object inside the Wrapper class -
public class Wrapper : IMyInterface
{
private IMyInterface _wrapped;
private LoginRequest _req;
public Wrapper(IMyInterface caller)
{
_wrapped = caller;
_req = new LoginRequest { ClientId = "ABCDEFG", ClientSecret = "123456" };
}
public int GetUserStuff(string userName)
{
return _wrapped.GetUserStuff(_req);
}
}
Usually, you will store the ClientId and ClientSecret values somewhere else (instead of hard coding them) and read them accordingly.
And, if you don't have access to the LoginRequest class from the Wrapper class (may be its on a separate layer/project that doesn't have the required assembly reference), then you can declare a class like ClientInfo and use it like -
public class ClientInfo
{
public string UserName { get; set; }
public string ClientId { get; set; }
public string ClientSecret { get; set; }
}
public class Wrapper : IMyInterface
{
private IMyInterface _wrapped;
private ClientInfo _info;
public Wrapper(IMyInterface caller)
{
_wrapped = caller;
_info = new ClientInfo { ClientId = "ABCDEFG", ClientSecret = "123456" };
}
public int GetUserStuff(string userName)
{
_info.UserName = userName;
return _wrapped.GetUserStuff(_info);
}
}
then the caller can create the LoginRequest object from the ClientInfo passed to it.
To slightly alter #atiyar's approach you can use an accessor. This is a generic version of what is used in core for the HTTPAccessor. The AsyncLocal will be set once for the main thread and then propagate to any threads spawned.
public class GenericAccessor<T> where T : class
{
private static AsyncLocal<Holder<T>> _current = new AsyncLocal<Holder<T>>();
public T Value
{
get => _current.Value?.Context;
set
{
var holder = _current.Value;
if (holder != null)
{
// Clear current trapped in the AsyncLocals, as its done.
holder.Context = null;
}
if (value != null)
{
// Use an object indirection to hold the in the AsyncLocal,
// so it can be cleared in all ExecutionContexts when its cleared.
_current.Value = new Holder<T> { Context = value };
}
}
}
private class Holder<T>
{
public T Context;
}
}
With the implementation
public class ClientInfo
{
public string ClientId { get; set; }
public string ClientSecret { get; set; }
}
public class UserInfo: ClientInfo
{
public UserInfo(ClientInfo clientInfo)
{
this.ClientId = clientInfo.ClientId;
this.ClientSecret = clientInfo.ClientSecret;
}
public string UserName { get; set; }
}
public interface IClientInfoAccessor
{
ClientInfo ClientInfo { get; set; }
}
public class ClientInfoAccessor : GenericAccessor<ClientInfo>, IClientInfoAccessor
{
public ClientInfo ClientInfo{ get => Value; set => Value = value; }
}
public class Wrapper: IMyInterface
{
private IMyInterface _wrapped;
private IClientInfoAccessor _accessor;
public Wrapper(IMyInterface caller, IClientInfoAccessor accessor)
{
_wrapped = caller;
_accessor = accessor;
}
public int GetUserStuff(string userName)
{
var req = new UserInfo(_accessor.ClientInfo);
req.UserName = userName;
return _wrapped.GetUserStuff(req);
}
}
All that you would need to do is to set the ClientInfo in middleware for each operation and you can use the accessor anywhere even in singletons.
Via DI container you can easily inject the IOption<> interface to the class constructor with:
public class Wrapper: IMyInterface
{
private IMyInterface_wrapped;
private MySettings _mySettings;
public Wrapper(IMyInterface caller, IOptions<MySettings> mySettings)
{
_wrapped = caller;
_mySettings = mySettings.Value;
}
private LoginRequest GetLoginRequest()
{
return new LoginRequest
{
ClientId = _mySettings.ClientId,
ClientSecret = _mySettings.ClientSecret
};
}
public FOO GetUserStuff(string userName)
{
return _wrapped.GetUserStuff(GetLoginRequest());
}
}
You can make it a static class and call a static method whenever it's needed. Or if you want to make it like in Angular you can add it to the pipeline (Startup Configure method):
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.Use(async (context, next) =>
{
LoginRequest req = new LoginRequest
{
ClientId = "ABCDEFG",
ClientSecret = "123456"
};
context.Response.Headers["ClientId"] = "ABCDEFG";
await next();
});
}
So I got these classes (JsonData are just a few classes with getters and setters for the Json value from the API):
GetSetJsonData:
class GetSetJsonData
{
HttpClient client;
#region SuccesLogin
JsonData.SuccesLogin.RootObject succesLogin;
JsonData.SuccesLogin.Session session;
JsonData.SuccesLogin.Data2 data2;
JsonData.SuccesLogin test;
#endregion
#region CompanyData
JsonData.CompanyData.RootObject companyDataMatchPage;
JsonData.CompanyData.RootObject companyDataMyNetwork;
JsonData.CompanyData.RootObject companyDataAllCompanies;
#endregion
//uristrings for connecting
string uriLoginString = "url";
string uriGetCompanies = "url";
public string sessionString { get; set; }
public bool MakeConnection(string email, string password)
{
succesLogin = new JsonData.SuccesLogin.RootObject();
session = new JsonData.SuccesLogin.Session();
data2 = new JsonData.SuccesLogin.Data2();
var userdata = new JsonData.UserLogin.Login()
{
userdata = new JsonData.UserLogin.Userdata()
{
user_email = email,
user_password = password
}
};
var content = new StringContent(JsonConvert.SerializeObject(userdata), Encoding.UTF8, "application/json");
client = new HttpClient();
var response = client.PostAsync(uriLoginString, content).Result;
var responseString = response.Content.ReadAsStringAsync().Result;
succesLogin = JsonConvert.DeserializeObject<JsonData.SuccesLogin.RootObject>(responseString);
if (succesLogin.success == null)
{
return false;
}
else
{
session = succesLogin.success.data.session;
sessionString = JsonConvert.SerializeObject(session);
data2 = succesLogin.success.data.data;
return true;
}
//implement failure system
}
//testing only
public void Test()
{
sessionString = JsonConvert.SerializeObject(session);
}
}
LoginPage:
public partial class LoginPage : ContentPage
{
//DummyData DD = new DummyData();
MasterDetailPageSetup masterDetail = new MasterDetailPageSetup();
GetSetJsonData getSetJsonData = new GetSetJsonData();
Test test = new Test();
public LoginPage()
{
InitializeComponent();
}
private void Button_Clicked(object sender, EventArgs e)
{
//Implement: return true of false when login is successful or not
if (Email.Text == null && Password.Text == null)
{
if (getSetJsonData.MakeConnection(Email.Text, Password.Text) == true)
{
//getSetJsonData.Test();
test.Help();
//var test = getSetJsonData.sessionString;
//masterDetail.SetupMasterDetailPage();
}
When I call MakeConnection from the LoginPage I get data in the GetSetJsonData class, no problem at all. Now when I call the Test() or the sessionString from the LoginPage it still works, BUT when I try to call this from any other class it for some reason only shows null values, even though I did save them. I just can't seem to make it work and I kinda gave up hope, anything to do this right?
You are creating the GetSetJsonData class as a new instance in LoginPage and also other Page. In this case, the GetSetJsonData class and also sessionString inside the class will only available inside LoginPage.
If you want to make the sessionString available for all places, you can have few options:
Make GetSetJsonData class as static class public static class GetSetJsonData
Make GetSetJsonData class as a Singleton class. Refer to HERE for more details
public class Singleton
{
private static Singleton instance;
private Singleton() {}
public static Singleton Instance
{
get
{
if (instance == null)
{
instance = new Singleton();
}
return instance;
}
}
}
Put GetSetJsonData instance as a public property in other static class or singleton class. For example: in App class.
public partial class App : Application
{
public GetSetJsonData GetSetJsonDataInstance { get; private set; }
public App()
{
InitializeComponent();
GetSetJsonDataInstance = new GetSetJsonData();
}
...
}
// Then you can access to the instance using:
((App)Application.Current).GetSetJsonDataInstance
I realized that I should have only one instance of an object called StdSchedulerFactory running at a time. So far I instantiated the object like this
StdSchedulerFactory sf = new StdSchedulerFactory(properties);
And properties is a NameValueCollection.
How can I write a Singleton class for this object so that the variable sf will always have one instance throughout the program?
Part of the Singleton pattern is typically a private constructor, so that other classes can not make new instances.
The workaround for parameters coming from outside the class is to add a "Init" or "Configure" function:
public static void Configure(NameValueCollection properties)
{
}
Of course, if you forget to call this function, you may get behavior you don't want; so you may want to set a "Configured" flag or something like that so your other functions can react appropriately if this function has not yet been called.
Here is a basic Singleton implementation. It is not thread-safe.
public sealed class StdSchedulerFactory
{
private static readonly StdSchedulerFactory instance;
private NameValueCollection _properties;
private StdSchedulerFactory(NameValueCollection properties)
{
_properties = properties;
}
public static StdSchedulerFactory GetInstance(NameValueCollection properties)
{
if (instance == null)
{
instance = new StdSchedulerFactory(properties);
}
else
{
return instance;
}
}
}
this is my two favorite way implementing simple singleton pattern. The second one is just easier when debugging :)
public sealed class SingletonOne
{
private static readonly Lazy<SingletonOne> instance = new Lazy<SingletonOne>(() => new SingletonOne());
private Lazy<Controller> controller = new Lazy<Controller>(() => new Controller(properties));
private static object properties = null;
public static SingletonOne Instance { get { return instance.Value; } }
public Controller GetController(object properties)
{
SingletonOne.properties = properties;
return this.controller.Value;
}
}
public sealed class SingletonTwo
{
private static readonly SingletonTwo instance = new SingletonTwo();
private Controller controller;
private static object properties = null;
public static SingletonTwo Instance
{
get
{
return SingletonTwo.instance;
}
}
public Controller GetController(object properties)
{
SingletonTwo.properties = properties;
if(this.controller == null)
{
this.controller = new Controller(SingletonTwo.properties);
}
return this.controller;
}
}
public class Controller
{
public Controller(object properties) { }
}