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
Related
How do I abstract the connection to my database away?
I am currently working on a nuget package, that sort of unify the way data is retrieved from the database,
thus ensuring that data is collected in a similar manner, regardless which service inherits it.
I though seem to be a bit confused of whether my inherited class, and the properties will be assessible for MyService?
and instantiated correctly?
Here is an example:
public class DataService : IDataservice
{
private readonly CosmosClient client;
public TestClass(CosmosClient client)
{
var kvUrl = Environment.GetEnvironmentVariable("KEY_VAULT_URL");
var secretclient = new SecretClient(new Uri(kvUrl), new DefaultAzureCredential());
var accountEndpoint = secretclient.GetSecret("AccountEndpoint-CosmosDb");
var accountKey = secretclient.GetSecret("AccountKey-CosmosDb");
this.client = new CosmosClientBuilder(accountEndpoint.Value.Value, accountKey.Value.Value).Build();
}
public IDictionary<string, object> GetForm(Guid id)
{
//Contains custom code for fetching form
//Processing fetched form'
//Return form
}
public object GetFormField(string propertyName)
{
//Contains custom code for fetching field
//Processing fetched field
//Return field
}
public string TestString()
{
return "Hello web";
}
}
public class MyService : DataService
{
public MyService()
{
}
public IDictionary<string, object> GetForm(Guid id) => return parent.GetForm(Guid id)
public object GetFormField(string propertyName) => return parent.GetFormField(string propertyName)
public override object GetFormField(string propertyName)
{
return "Hello new world";
}
}
does Myservice have an instantiated version of the CosmosClient?
Is GetForm and GetFormField accessible to MyService - and is it possible to explictly state when an inherited method is overridden as above?
and is this even a good idea? - I feel like I am creating an unessary layer, to ensure that data is fetched uniformly by making a class that everyone can inherit.
I think you could do something like this:
public class TestClass
{
private CosmosClient _client;
private SecretClient _secretClient;
public string kvUrl { get => Environment.GetEnvironmentVariable("KEY_VAULT_URL"); }
public SecretClient secretClient {
get
{
return _secretClient ?? (_secretClient = new SecretClient(new Uri(kvUrl), new DefaultAzureCredential()));
}
}
public KeyVaultSecret accountEndpoint {
get
{
return _secretClient.GetSecret("AccountEndpoint-CosmosDb");
}
}
public KeyVaultSecret accountKey {
get
{
return _secretClient.GetSecret("AccountKey-CosmosDb");
}
}
public CosmosClient client {
get
{
return _client ?? (_client = new CosmosClientBuilder(accountEndpoint.Value, accountKey.Value).Build());
}
}
}
Why dont you make an abstract class for DataService, and set the secrets/connections from the derived classes.
as
public abstract class DataService
{
public DataService(CosmosClient client)
{
var kvUrl = Environment.GetEnvironmentVariable("KEY_VAULT_URL");
var secretclient = new SecretClient(new Uri(kvUrl), new DefaultAzureCredential());
var accountEndpoint = secretclient.GetSecret("AccountEndpoint-CosmosDb");
var accountKey = secretclient.GetSecret("AccountKey-CosmosDb");
this.client = new CosmosClientBuilder(accountEndpoint.Value.Value, accountKey.Value.Value).Build();
}
// your abstract methods here to be implementd by derived classes
}
class some_derived_class:DataService{
some_derived_class:DataService(CosmosClient client):base(client){}
}
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();
});
}
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; }
}
I got a class that handles the proxys for a project i bought. And i am looking for learning while doing some modifications to this project.
My question is how can i get a variabel from a void call? I supose the call Proxy.NewProxy(); is the one that grabs the new proxy from my list. But what i want to do is to make a variable of the proxy it got so i can list it in a logfile for example.
My class looks like this
class Proxy
{
private static List<string> proxies = new List<string>();
private static int proxyIndex = 0;
public static WebProxy GetProxy()
{
string[] proxy = proxies[proxyIndex].Split(':');
WebProxy wp = new WebProxy(proxy[0], Convert.ToInt32(proxy[1]));
return wp;
}
public static void NewProxy()
{
if (proxyIndex < proxies.Count - 1)
{
proxyIndex++;
}
else
{
proxyIndex = 0;
}
}
public static void AddProxy(string proxy)
{
proxies.Add(proxy);
}
public static void ClearProxy()
{
proxies.Clear();
}
public static void RemoveProxy(string proxy)
{
proxies.RemoveAll(a => a == proxy);
}
public static List<string> ListProxy()
{
return proxies;
}
}
You can add an event to your class:
public class ProxyGivenEventArgs : EventArgs
{
public String ProxyName { get; private set; }
public ProxyGivenEventArgs(String proxyName)
{
this.ProxyName = proxyName;
}
}
public static class Proxy
{
// ...
public static event EventHandler<ProxyGivenEventArgs> ProxyGiven;
private static void OnProxyGiven(String proxyName)
{
if (Proxy.ProxyGiven != null)
Proxy.ProxyGiven(null, new ProxyGivenEventArgs(proxyName));
}
public static WebProxy GetProxy()
{
string[] proxy = proxies[proxyIndex].Split(':');
WebProxy wp = new WebProxy(proxy[0], Convert.ToInt32(proxy[1]));
OnProxyGiven(proxy[0]);
return wp;
}
// ...
}
and use it like:
Proxy.ProxyGiven += (sender, args) =>
{
Logger.Log("Proxy {0} is given.", args.ProxyName);
};
P.S.: You can tailor ProxyGivenEventArgs to include more info that will suit your needs.
For example if you need the instance of the instantiated proxy, then you can:
public class ProxyGivenEventArgs : EventArgs
{
public WebProxy ProxyInstance { get; private set; }
public ProxyGivenEventArgs(WebProxy proxy)
{
this.ProxyInstance = proxy;
}
}
//...
private static void OnProxyGiven(WebProxy proxy)
{
if (Proxy.ProxyGiven != null)
Proxy.ProxyGiven(null, new ProxyGivenEventArgs(proxy));
}
public static WebProxy GetProxy()
{
string[] proxy = proxies[proxyIndex].Split(':');
WebProxy wp = new WebProxy(proxy[0], Convert.ToInt32(proxy[1]));
OnProxyGiven(wp);
return wp;
}
and use it like:
Proxy.ProxyGiven += (sender, args) =>
{
Logger.Log("Proxy {0} is given.", args.ProxyInstance.ToString());
};
P.S.1: If you aren't familiar with event model you may want to read this MSDN article.