Reference object in two classes C# - c#

Let's go straight to my probably fairly simple problem.
I have a LoginService class in my Services folder which makes a connection with the server. I have another UserModel where I want to receive information from the server. In order not to login again (which would be stupid), I need to maintain the client reference in both files having the same value. In other words, I need to be able to access the same object from a different class (make another reference).
I have tried and tried and searched but I am missing something.
A fairly similar post that I found that still didn't solve mine is this.
The code in my LoginService:
namespace App_Name.Services
{
class LoginService
{
public static Class_Name client;
public async Task MakeConnectionAsync(string userToken)
{
client = new Class_Name();
PasswordVault vault = new PasswordVault();
await client.LoginAsync(TokenType.User, userToken);
await client.StartAsync();
}
So now I want to get the user avatar on my UserModel.cs:
namespace App_Name.Models
{
class UserModel
{
public string GetAvatar()
{
return LoginService.client.CurrentUser.GetAvatarUrl();
}
But it always gives an exception because it tries but there is no connection.
I am sure that it was Connected because in order to load the UserModel it has to be a successful connection.
Any ideas ?

When you call directly the client.CurrentUser.GetAvatarUrl() method, its not determined by the LoginService class. You should be create the Login class before the usage. Also you are using async tasks on your LoginService class, you must confirm that already create user by your UserModel class.
For best practice you can create instance with your constructor like this.
static class LoginService
{
public static Class_Name client;
static LoginService()
{
client = new Class_Name();
}
If you want to go with static (which I not prefer for service level) not use static for like this purpose of usage.
Firstly you should be check dependency injection concepts; i suggest unity and structuremap containers. You can create your consume services by your classes without any object null ref. exception. Dependency injection decrease on coupling and null reference exception.

Ehmmm, for anyone that can use this as a reference, my code above is just fine.
The problem was with the connection API not returning the status immediately. A delay of 2 seconds solved my problem. Thanks everyone for their help.

Related

How do you send out from SignalR Hub from another class in the same project?

Background: I'm on .Net 6 running the latest and greatest from the built-in SignalR package. I installed #microsoft/signalr and the JS side of things works fine for Client -> Server communications. The issue is my Server -> Hub communications.
I have a class that after updating some information and needs to broadcast out to whomever is listening that "this object was updated". Below is what I'm talking about.
public class SignalRRunner
{
public SignalRRunner(ICompanyDIContainer companyContainer)
: base(companyContainer)
{
}
public Task RunItAsync(Signal signal)
{
if (signal.userId.HasValue)
{
// Do work on the thing, update the db, etc. here
await ChatHub.Static_Send("debug", "users", "accounts", userObject);
return Task.FromResult(true);
}
return Task.FromResult(false);
}
}
In my hub:
public static async Task Static_Send(string group, string whoUpdate, string whatUpdate, object payload)
{
if (string.IsNullOrWhiteSpace(group))
{
group = "debug";
}
await Clients.Group(group).SendAsync("OnDebug", payload, new CancellationToken());
}
Due to limitations imposed from my company, I cannot directly inject the IHubContext into the constructor of anything as they use their own version of DI in the project and it always throws an exception when I've tried. I've tried making the function non-static, registering the ChatHub in startup.cs, and resolving it in the class that's doing the work, but the Clients are null and this throws an error. Every other solution I've read suggests using the GlobalHost.ConnectionManager.GetHubContext to get the HubContext from inside the static method, but that's no longer part of SignalR so that's out. How do I send messages to the ChatHub from another class inside the same project?
I figured out how to accomplish this. What I did was add the SignalR client package to my project and created a hub connection. I added it to the IoC container we use as a singleton and just resolve it wherever I need.

How to manage the HttpClient instance in a class library

I'm writing a .Net Core class library that is a wrapper around a REST web service. I'm using HttpClient which should be instantiated as a singleton.
The big question I have now is how should I manage this HttpClient instance? Should it be the role of my class library, or of the calling code that would pass the instance to my class library.
I started with the first solution, creating a singleton instance this way:
public class DemoClient : IDemoClient
{
private static readonly HttpClient HttpClient;
static DemoClient()
{
HttpClient = new HttpClient();
}
public DemoClient(Uri baseUrl)
{
HttpClient.BaseAddress = baseUrl;
}
}
I use the static constructor to instantiate the singleton instance and set the baseUrl in the "standard" constructor.
There's a few things I don't like about this approach. First, if the user of my class library creates a second instance of the class, setting the baseUrl to something else, it will break completely, first because once a query has been made, setting the BaseAddress throws an exception and secondly because even if you could, it would not be possible for each instance to have a different BaseAddress.
This means that either I force the user to create a singleton of my class which means that he wouldn't be able to create two instances for two different REST endpoint or I forget about making the HttpClient instance singleton but this might end up being a bad idea with the risk of wasting sockets.
The second solution would mean I'd simply leave the instantiation of the HttpClient to the user of my library, and ask him to pass it to my constructor. It would definitely simplify the management (at least for me :)) but it feels like leaking implementation details.
I might in the future change and use a different approach than HttpClient and this shouldn't have any impact of the user of my library. Moreover, it asks the user of the library to actually know how to use the HttpClient (and how to use it correctly), which doesn't feel "right" as well.
Is there another option I haven't thought about? This issue of having the HttpClient instance a singleton is quite annoying...

SslStream, disable session caching

The MSDN documentation says
The Framework caches SSL sessions as they are created and attempts to reuse a cached session for a new request, if possible. When attempting to reuse an SSL session, the Framework uses the first element of ClientCertificates (if there is one), or tries to reuse an anonymous sessions if ClientCertificates is empty.
How can I disable this caching?
At the moment I am experiencing a problem with a reconnect to a server (i.e., the first connection works good, but at attempt to reconnect the servers breaks the session). Restarting the application helps (but of course only for the first connection attempt). I assume the problem root is caching.
I've checked the packets with a sniffer, the difference is at just single place only at Client Hello messages:
First connection to the server (successful):
Second connection attempt (no program restart, failed):
The difference seems to be just the session identifier.
P.S. I'd like to avoid using 3rd-party SSL clients. Is there a reasonable solution?
This is a translation of this question from ru.stackoverflow
Caching is handled inside SecureChannel - internal class that wraps SSPI and used by SslStream. I don't see any points inside that you can use to disable session caching for client connections.
You can clear cache between connections using reflection:
var sslAssembly = Assembly.GetAssembly(typeof(SslStream));
var sslSessionCacheClass = sslAssembly.GetType("System.Net.Security.SslSessionsCache");
var cachedCredsInfo = sslSessionCacheClass.GetField("s_CachedCreds", BindingFlags.NonPublic | BindingFlags.Static);
var cachedCreds = (Hashtable)cachedCredsInfo.GetValue(null);
cachedCreds.Clear();
But it's very bad practice. Consider to fix server side.
So I solved this problem a bit differently. I really didn't like the idea of reflecting out this private static method to dump the cache because you don't really know what you're getting into by doing so; you're basically circumventing encapsulation and that could cause unforeseen problems. But really, I was worried about race conditions where I dump the cache and before I send the request, some other thread comes in and establishes a new session so then my first thread inadvertently hijacks that session. Bad news... anyway, here's what I did.
I stopped to think about whether or not there was a way to sort of isolate the process and then an Android co-worker of mine recalled the availability of AppDomains. We both agreed that spinning one up should allow the Tcp/Ssl call to run, isolated from everything else. This would allow the caching logic to remain intact without causing conflicts between SSL sessions.
Basically, I had originally written my SSL client to be internal to a separate library. Then within that library, I had a public service act as a proxy/mediator to that client. In the application layer, I wanted the ability to switch between services (HSM services, in my case) based on the hardware type, so I wrapped that into an adapter and interfaced that to be used with a factory. Ok, so how is that relevant? Well it just made it easier to do this AppDomain thing cleanly, without forcing this behavior any other consumer of the public service (the proxy/mediator I spoke of). You don't have to follow this abstraction, I just like to share good examples of abstraction whenever I find them :)
Now, in the adapter, instead of calling the service directly, I basically create the domain. Here is the ctor:
public VCRklServiceAdapter(
string hostname,
int port,
IHsmLogger logger)
{
Ensure.IsNotNullOrEmpty(hostname, nameof(hostname));
Ensure.IsNotDefault(port, nameof(port), failureMessage: $"It does not appear that the port number was actually set (port: {port})");
Ensure.IsNotNull(logger, nameof(logger));
ClientId = Guid.NewGuid();
_logger = logger;
_hostname = hostname;
_port = port;
// configure the domain
_instanceDomain = AppDomain.CreateDomain(
$"vcrypt_rkl_instance_{ClientId}",
null,
AppDomain.CurrentDomain.SetupInformation);
// using the configured domain, grab a command instance from which we can
// marshall in some data
_rklServiceRuntime = (IRklServiceRuntime)_instanceDomain.CreateInstanceAndUnwrap(
typeof(VCServiceRuntime).Assembly.FullName,
typeof(VCServiceRuntime).FullName);
}
All this does is creates a named domain from which my actual service will run in isolation. Now, most articles that I came across on how to actually execute within the domain sort of over-simplify how it works. The examples typically involve calling myDomain.DoCallback(() => ...); which isn't wrong, but trying to get data in and out of that domain will likely become problematic as serialization will likely stop you dead in your tracks. Simply put, objects that are instantiated outside of DoCallback() are not the same objects when called from inside of DoCallback since they were created outside of this domain (see object marshalling). So you'll likely get all kinds of serialization errors. This isn't a problem if running the entire operation, input and output and all can occur from inside myDomain.DoCallback() but this is problematic if you need to use external parameters and return something across this AppDomain back to the originating domain.
I came across a different pattern here on SO that worked out for me and solved this problem. Look at _rklServiceRuntime = in my sample ctor. What this is doing is actually asking the domain to instantiate an object for you to act as a proxy from that domain. This will allow you to marshall some objects in and out of it. Here is my implemenation of IRklServiceRuntime:
public interface IRklServiceRuntime
{
RklResponse Run(RklRequest request, string hostname, int port, Guid clientId, IHsmLogger logger);
}
public class VCServiceRuntime : MarshalByRefObject, IRklServiceRuntime
{
public RklResponse Run(
RklRequest request,
string hostname,
int port,
Guid clientId,
IHsmLogger logger)
{
Ensure.IsNotNull(request, nameof(request));
Ensure.IsNotNullOrEmpty(hostname, nameof(hostname));
Ensure.IsNotDefault(port, nameof(port), failureMessage: $"It does not appear that the port number was actually set (port: {port})");
Ensure.IsNotNull(logger, nameof(logger));
// these are set here instead of passed in because they are not
// serializable
var clientCert = ApplicationValues.VCClientCertificate;
var clientCerts = new X509Certificate2Collection(clientCert);
using (var client = new VCServiceClient(hostname, port, clientCerts, clientId, logger))
{
var response = client.RetrieveDeviceKeys(request);
return response;
}
}
}
This inherits from MarshallByRefObject which allows it to cross AppDomain boundaries, and has a single method that takes your external parameters and executes your logic from within the domain that instantiated it.
So now back to the service adapter: All the service adapters has to do now is call _rklServiceRuntime.Run(...) and feed in the necessary, serializable parameters. Now, I just create as many instances of the service adapter as I need and they all run in their own domain. This works for me because my SSL calls are small and brief and these requests are made inside of an internal web service where instancing requests like this is very important. Here is the complete adapter:
public class VCRklServiceAdapter : IRklService
{
private readonly string _hostname;
private readonly int _port;
private readonly IHsmLogger _logger;
private readonly AppDomain _instanceDomain;
private readonly IRklServiceRuntime _rklServiceRuntime;
public Guid ClientId { get; }
public VCRklServiceAdapter(
string hostname,
int port,
IHsmLogger logger)
{
Ensure.IsNotNullOrEmpty(hostname, nameof(hostname));
Ensure.IsNotDefault(port, nameof(port), failureMessage: $"It does not appear that the port number was actually set (port: {port})");
Ensure.IsNotNull(logger, nameof(logger));
ClientId = Guid.NewGuid();
_logger = logger;
_hostname = hostname;
_port = port;
// configure the domain
_instanceDomain = AppDomain.CreateDomain(
$"vc_rkl_instance_{ClientId}",
null,
AppDomain.CurrentDomain.SetupInformation);
// using the configured domain, grab a command instance from which we can
// marshall in some data
_rklServiceRuntime = (IRklServiceRuntime)_instanceDomain.CreateInstanceAndUnwrap(
typeof(VCServiceRuntime).Assembly.FullName,
typeof(VCServiceRuntime).FullName);
}
public RklResponse GetKeys(RklRequest rklRequest)
{
Ensure.IsNotNull(rklRequest, nameof(rklRequest));
var response = _rklServiceRuntime.Run(
rklRequest,
_hostname,
_port,
ClientId,
_logger);
return response;
}
/// <summary>
/// Releases unmanaged and - optionally - managed resources.
/// </summary>
public void Dispose()
{
AppDomain.Unload(_instanceDomain);
}
}
Notice the dispose method. Don't forget to unload the domain. This service implements IRklService which implements IDisposable, so when I use it, it used with a using statement.
This seems a bit contrived, but it's really not and now the logic will be run on it's own domain, in isolation, and thus the caching logic remains intact but non-problematic. Much better than meddling with the SSLSessionCache!
Please forgive any naming inconsistencies as I was sanitizing the actual names quickly after writing the post.. I hope this helps someone!

How to pass an object to a web service?

I already searched a lot in Google.
I created a EntityClass on client side, and then I added the library reference of this class on Web Service side. But when I want to call the method, it shows this error:
Error 2 Argument 1: cannot convert
from
'Services_Library.UserService.UserServiceSoapClient'
to
'Services_Library.UserService.UserEntity'
here is the code, this method is called from a User Interface:
public UserEntity test(UserEntity userEntityx)
{
UserService.UserServiceSoapClient userService = new UserService.UserServiceSoapClient();
userService.testUserAsync(new UserEntity());
}
I think we can do this without explicit serialization, right? If so, I prefer this way.
I think the problem is when you actually call the service, you're passing in the serviceReference and not the object that the call accepts. I think it should look something like:
public UserEntity test(UserEntity userEntityX)
{
var userService = new UserService.UserServiceSoapClient();
return userService.testUser(userEntityX);
}
No explicit serialization needed.
Also, keep in mind that if you're calling the Async version of the method you're code is going to become more complicated. I used the synchronous version in my example.

.NET Remoting: how to access server application objects from remotable object?

I'm writing a windows service application, which will be accessed through .NET Remoting.
The problem is I can't figure out how to access service objects from remotable class.
For example, I've a handler class:
class Service_console_handler
{
public int something_more = 20;
//some code...
TcpChannel serverChannel = new TcpChannel(9090);
ChannelServices.RegisterChannel(serverChannel);
RemotingConfiguration.RegisterWellKnownServiceType(
typeof(RemoteObject), "RemoteObject.rem",
WellKnownObjectMode.Singleton);
//from here on RemoteObject is accessible by clients.
//some more code doing something and preparing the data...
}
And I've a remotable class:
public class RemoteObject : MarshalByRefObject
{
private int something = 10;
public int Get_something()
{
return something;
}
}
Clients can access data in RemoteObect with no problem. But how can I access Service_console_handler object (i.e. to retrieve useful info from something_more)?
Sorry for dumb questions and thanks in advance.
What you want is somehow to access the instance of ServiceConsoleHandler via a RemoteObject instance, which is visible for the client.
For this you need to consider two things: (1) Get control over the object construction of the RemoteObject instance and make it accessible and (2) modify ServiceConsoleHandler so it can be accessed remotely.
(1)
How would you construct a RemoteObject instance in ServiceConsoleHandler, if you don’t need to consider remoting?
I guess you would do something like this:
class ServiceConsoleHandler
{
…
RemoteObject remoteObject = new RemoteObject();
// now assume that you also already have
// modified the RemoteObject class so it can hold
// a reference to your server:
remoteObject.Server = this;
…
}
It would be nice if you could make this object accessible for the client. You can do this by using RemotingServices.Marshal instead of RemotingConfiguration.RegisterWellKnownServiceType:
class ServiceConsoleHandler
{
…
TcpServerChannel channel = new TcpServerChannel(9090);
ChannelServices.RegisterChannel(channel, true);
RemoteObject remoteObject = new RemoteObject();
remoteObject.Server = this;
RemotingServices.Marshal(remoteObject, "RemoteObject.rem");
…
}
(2)
If you execute the code right now and access the remoteObject.Server in the client code you would get some remoting exception, because the class ServiceConsoleHandler cannot be accessed remotely. Therefore you need the add the [Serializable] attribute:
[Serializable]
class ServiceConsoleHandler
{ … }
Reason: Types which should be accessed remotely, need to be marshaled to some special transferrable representation. This way they can be squeezed through the TCP port and transferred via the TCP protocol. Basic data types can by marshaled by the framework, so you don't need to think about them. For custom types you will need to state, how to do this. One way to do this is by subclassing from MarshalByRefObject. That’s exactly what you have already done with RemoteObject. Another way is to mark your custom classes as [Serializable] as shown above.
That’s it. Now you should be able to access the server’s field in the client code. Note that you don’t need your existing code for object activation:
TcpClientChannel channel = new TcpClientChannel();
ChannelServices.RegisterChannel(channel, true);
RemoteObject remoteObject = (RemoteObject)Activator.GetObject(
typeof(RemoteObject), "tcp://localhost:9090/RemoteObject.rem");
Console.WriteLine(remoteObject.Server.SomethingMore);
For me .NET remoting is full of funny surprises and sleepless nights. To counter this, make yourself familiar with the remoting concepts (which are from my point of view poorly documented). Dig into the serialization concept (MarshalByRefObject vs. [Serializable]). If you want to make a production code out of it, think a very good ways to handle remoting exceptions. Also consider multithreading. There could be more than one client using this remote object at once.
Have fun!
Thank you! I very much appreciate thoroughness and clarity of you answer.
Most bizzare thing is that I didn't even know that you can publish object instance. About a dozen simple tutorials I studied proposed RemotingConfiguration.RegisterWellKnownServiceType as only method to do remoting. Stupid me.
Now remoting looks much more useful to me. I just wrote a quick test application and it worked. Thanks again.

Categories

Resources