MarshalByRefObject Lifetime - c#

I have a .net WinForms application that loads plugins (dlls) into their own AppDomains, each dll gets its own AppDomain using domain.CreateInstanceAndUnwrap(). All i want is, that these objects remain connected forever (till the application stops).
The InitialLeaseTime is 5 minutes, but i can't find a way to change that. ..
I tried overriding InitializeLifetimeService() of the remote object:
Public Overrides Function InitializeLifetimeService() As Object
Return Nothing
End Function
Here I get a Typeload-Exception, saying that this would break the inheritance rules.
Adding
<SecurityPermissionAttribute(SecurityAction.Demand, Flags:=SecurityPermissionFlag.Infrastructure)>
<SecuritySafeCritical>
doesn't change anything.
Then:
Dim tmpObj As Object = domain.CreateInstanceAndUnwrap(type.AssemblyName, type.TypeName)
Dim tmpRemote As tmpRemoteType = CType(tmpObj, tmpRemoteType)
Dim lifetimeService As Object = Runtime.Remoting.RemotingServices.GetLifetimeService(tmpRemote)
Dim lease As ILease = TryCast(lifetimeService, ILease)
If (lease IsNot Nothing) Then
lease.Register(_sponsor)
End If
Doesn't do it neither, because somehow the Renewal() method of the sponsor (not shown here) is never called.
Calling
lease.Renew(TimeSpan.FromMinutes(300))
directly changes the CurrentLeaseTime but not the InitialLeaseTime of the lease.
Finally i tried calling the shared (static) property LeaseTime, which actually led to a change of CurrentLeaseTime at the beginning of the Lease, but again NOT the InitialLeaseTime, which seems to end after 5 minutes and my remote object being gc'ed:
LifetimeServices.RenewOnCallTime = System.TimeSpan.FromMinutes(300)
Any help is appreciated,
Thx!

Not sure what's going on, but here's how it works
var sponsor = new Sponsor(); // manages lifetime of the object in otherDomain
var target = otherDomain.CreateInstanceFromAndUnwrap(assemblyFilename, typeFullName)
as MarshalByRefObject;
var lease = target.InitializeLifetimeService() as ILease;
lease.Register(sponsor);
In this case, it is only important that you retain references to target (obvious) and sponsor. Sponsor is a class that manages the subscription:
class Sponsor : MarshalByRefObject, ISponsor
{
public bool Release { get; set; }
public TimeSpan Renewal(ILease lease)
{
// if any of these cases is true
if (lease == null || lease.CurrentState != LeaseState.Renewing || Release)
return TimeSpan.Zero; // don't renew
return TimeSpan.FromSeconds(1); // renew for a second, or however long u want
}
}
When you're done with it, simply set Release to true on the sponsor and let it go. You could also do this by implementing IDisposable on Sponsor to handle this, if that tickles your fancy.

Related

If I use a static method to create an object and add it to a disposable instance of another object, is the object created in the static method static?

I am seeing some strange, buggy behavior in some .NET code, and I'm wondering if it has to do with how I've set things up.
I have a non-static class with a method. In this method, I create a new instance of a disposable class. I then use a static helper method to add something to that disposable instance.
Sometimes the code throws an exception at a certain point (by timing out). I don't know why, and this question isn't about why that happens. But what happens next is that if an exception was thrown, the next time the code runs, which supposedly would create a new instance of my main class, and a new instance of the disposable object within that new instance, then a different bit of code involving the disposable object also causes a timeout exception, much earlier in the process.
Here is a simplified example of what's happening:
public sealed class MyClass : OtherClass
{
protected override void MyMethod(ContextInfo context)
{
using (DisposableClass disposableInstance = new DisposableClass(context.URL))
{
Helper.ConditionallyAddThingy(disposableInstance, context.thingInfo, context.URL);
foreach(var foo in fooCollection)
{
// 1. initially I can make as many of these calls as I want,
// and they all finish successfully. if there were no
// timeout issues in section 2 below, the next time this
// runs, supposedly in a new instance of MyClass, and with
// a new instance of "disposableInstance", it again runs perfectly fine,
// no matter how many "foo"s there are.
// 2. see below
// 3. _if_ I had a timeout exception previously in section 2 below,
// the next time this runs, supposedly in a _new_ instance of MyClass,
// and with a _new_ instance of "disposableInstance",
// I get a timeout exception _here_ on the first "foo", and don't even get to section 2.
// make a call that does _not_ have to do with file streams
SomeResponse response = disposableInstance.AskForSomething(foo);
disposableInstance.ExecuteQuery();
}
foreach(var fileInfo in fileInfoCollection)
{
// 2. if there is only one file, the call succeeds, however
// if there is more than one file, the request for the
// second file casuses a System.Net.WebException: The operation has timed out
var fileUrl = fileInfo["URL"];
FileIshThing fileIsh = File.OpenBinaryDirect(disposableInstance, fileUrl);
disposableInstance.ExecuteQuery();
}
}
}
}
internal static class Helper
{
internal static void ConditionallyAddThingy(DisposableClass disposableInst, string thingInfo string contextUrl)
{
if (!string.IsNullOrWhiteSpace(thingInfo))
{
Thing thing = new Thing(thingInfo);
Uri uri = new Uri(contextUrl);
thing.Uri = uri;
ThingCollection collection = new ThingCollection();
collection.Add(thing);
disposabeInst.ExecuteWebRequestEventHandler += delegate (object sender, EventArgs eventArgs)
{
eventArgs.ThingCollection = collection;
}
}
}
}
Is there something about creating the Thing or ThingCollection, or adding the event receiver in the static method that makes those things static themselves, so that the next time through, I'm not really creating new ones but reusing the ones from the last time the method executed?
I don't understand how an error condition in a previous (and disposed of) instance of an object can affect a new instance of the object that may not necessarily meet the conditions for causing the error.

Asp.Net Core class not passing data

In asp.net core 2.1 Identity I am using a class to move the login name from ExternalLogin.cshtml.cs and Login.cshtml to save them to another table via a class AddUserToStudentTable.
EDIT - I have got the terminology of DTO wrong, but consider it just a class that pushes data around. I just used the wrong naming convention.
The class is
public class StudentNameDTO : IStudentNameDTO
{
public string StudentGoogleNameLogin { get; set; } = string.Empty;
public bool IsExternal { get; set; } = false;
}
The Startup is using AddSingleton but I have also tried AddTransient, with no difference.
services.AddSingleton<IStudentNameDTO, StudentNameDTO>();
And I am using the usual Constructor injection automatically done with wonderful VS 2017
Yet when passing data I always get an error of
evaluation of method () calls into native method system System.Environment.FailFast().
and it all crashes down with
NullReferenceException: Object reference not set to an instance of an object.
ASPNZBat.Business.AddUserToStudentTable.AddUserToStudent(string Email) in AddUserToStudentTable.cs + if (_studentNameDTO.IsExternal == true) ASPNZBat.Areas.Identity.Pages.Account.ExternalLoginModel.OnGetCallbackAsync(string returnUrl, string remoteError) in ExternalLogin.cshtml.cs + _addUserToStudentTable.AddUserToStudent(Email);
I have tried using AddTransient and AddScope as well in the startup, but no difference. Having worked on it for hours I am starting to doubt my ability to program....
Note that when there is data passing through it works OK. But when there is no data - null - instead of working with it it just crashes. I even wrapped it in a boolean to see if I could catch the output with that but it crashed at the boolean as well.
Data going in
if (info.Principal.Identity.Name != null)
{
_studentNameDTO.IsExternal = true;
_studentNameDTO.StudentGoogleNameLogin = info.Principal.Identity.Name;
string Email = info.Principal.FindFirstValue(ClaimTypes.Email);
_addUserToStudentTable.AddUserToStudent(Email);
}
Data coming out
string StudentName = string.Empty;
if (_studentNameDTO.IsExternal == true)
{
StudentName = _studentNameDTO.StudentGoogleNameLogin;
}
There is something about passing null data that it doesn't like and I don't understand.
Here is the github acc for it https://github.com/Netchicken/ASPNZBatV2/tree/master/ASPNZBat
It looks like you've got a case of Over-Dependency Injection.
Aside: You almost certainly don't want to be using AddSingleton here, a singleton is something that you want your application to have no more than one instance of during its execution. In this instance that would mean that if you had two users logging (or whatever the process is here) in at the same time they would both share the same instance of StudentNameDTO.
Based on the code in AddUserToStudentTable.cs the reason you're seeing a NullReferenceException is that there's nothing here that assigns to _studentNameDTO prior to it being used. It's not being injected anywhere, nor is it being passed into the class anywhere, it's declared private so isn't accessible from outside the class and is only read from on lines 36 and 38.
That said, not everything in your code needs, or should, be instantiated via Dependency Injection. Your StudentNameDTO isn't something the class depends on, it's something it consumes / modifies. From a cursory look at your code, it looks like the place that obtains all the data that's stored into StudentNameDTO is in ExternalLoginModel.OnGetCallbackAsync so this is where you should var studentNameDto = new StudentNameDTO() before calling AddUserToStudent and passing the instance of StudentNameDTO into the method, e.g. (line 97 onwards):
if (info.Principal.Identity.Name != null)
{
var studentNameDto = new StudentNameDTO
{
IsExternal = true,
_studentNameDTO.StudentGoogleNameLogin = info.Principal.Identity.Name
};
string Email = info.Principal.FindFirstValue(ClaimTypes.Email);
_addUserToStudentTable.AddUserToStudent(studentNameDto, Email);
}

Proper way to setup a flag across entire site

I have multiple partial views that must be shown if a flag is set to true accross the entire site.
I have that flag hardcoded inside appSettings on my web.config file and is working nice. But now this flag must be set trough our back-end.
The site has a lot of traffic and I need a proper way to reach that, I feel like making a SQL request just to check this flag is an overkill.
I've though about reading a simple txt file containing the flag, but I dont know if it's still "too much".
How would be the most optimized way?
Check out MemoryCache. You can create a basic static class with a static property to return the cached flag value, and then you can define an absolute expiration to whatever comfort level you can live with (5 second or 60 minutes or any timespan) upon which you'd update the value in the cache.
Here is a very quick example to handle threading.
public static class CacheStore
{
private static readonly string _keyMySharedFlag = "shared.flag";
private static readonly object _lockMySharedFlag = new object();
public static bool MySharedFlag
{
get
{
var cachedFlag = (bool?)MemoryCache.Default.Get(_keyMySharedFlag);
if (cachedFlag != null)
return cachedFlag.Value;
lock (_lockMySharedFlag)
{
// Confirm no other threads wrote to cache while we waited
cachedFlag = (bool?)MemoryCache.Default.Get(_keyMySharedFlag);
if (cachedFlag != null)
return cachedFlag.Value;
bool? newFlag = true; // Set to your database value
var cachePolicy = new CacheItemPolicy();
cachePolicy.AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(5); // 5 minutes
MemoryCache.Default.Set(_keyMySharedFlag, newFlag, cachePolicy);
return newFlag.Value;
}
}
}
}
I would suggest define a global configuration class which has all the flags, common data in it and use Dependency Injection to inject it to where ever you need. This will result in a more testable solution I believe.

How to access a running .net application

the .net Windows Form application we developed (vb.net but c# answer is ok too) has some APIs (edit: yes, our own) to allow users to automate some tasks.
Everything is fine when the application is started through APIs by, say, Visual Studio. What we cannot get to work though is to assign an already running instance of our application to a new application object in visual studio.
We have seen there are some methods available for COM objects (getojbect) to access a running instance of an application but how about .net applications?
Rephrasing the question, we would like that, when a user calls the New() constructor of our application, the new object points to the running instance of our application (if any) instead of trying to create a new one (which is not possible by the way because we have made it single instance by checking through Mutex that no other instance of our application is running).
EDIT:
Sample code in the user application to automate some tasks
Imports TheApplication
Public Class WinFormByUser
Private ApplicationObject As TheApplication.MainForm
Public Sub OpenTheApplication()
ApplicationObject = New TheApplication.MainForm
Rem here theapplication should create a new instance if no instance of TheApplication is running. BUT, if an instance of the application
Rem is already running (in a different process, maybe started directly from the user), the ApplicationObject should point to the running
Rem instance from now on, instead of trying to create a new instance
ApplicationObject.DoSomething()
End Sub
End Class
Sample code inside TheApplication
Imports System.Threading
Public Class MainForm
Private ApplicationOpenedThroughAPI As Boolean = False
Private Shared mtx As Mutex
Private firstInstance As Boolean = False
Dim AppName As String = "TheApplicationName"
Public Sub New()
If Application.ProductName.ToString() <> AppName Then
Rem if TheApplication is opened externally through API the name is different therefore we can determine the boolean value
ApplicationOpenedThroughAPI = True
End If
mtx = New Mutex(True, AppName, firstInstance)
If firstInstance Then
InitializeComponent()
DoAllTheNecessaryStuff()
Else
If ApplicationOpenedThroughAPI = False Then
MsgBox("Application is running, can't open second instance")
Else
ReturnTheRunningInstance()
End If
End If
End Sub
Private Sub ReturnTheRunningInstance()
Rem please help here. what to do?
End Sub
Public Sub DoSomething()
Rem this does something and can be called by API user
End Sub
End Class
Please note that the solution could either be adding some code inside the application in the Sub ReturnTheRunningInstance() or in the user code, maybe checking if the application is running through something like Process.GetProcessesByName("TheApplicationName").Length and then do something in case.
Thanks!
We have seen there are some methods available for COM objects
(getojbect) to access a running instance of an application but how
about .net applications?
Let's start with this part. You essentially need to have one process access another process. .Net provides a variety of forms of cross-process communication. WCF seems the most appropriate here.
WCF is a large subject, but here's a basic architecture that might accomplish your goals.
Step 1
Have your application host a service, available to local callers over TCP.
Consider this pseudocode; there is plenty of documentation available on WCF once you know what to search for.
// the contract
[ServiceContract]
public interface IMyService
{
[OperationContract]
int Foo( int bar );
}
// the implementation
public MyService : IMyService
{
public int Foo( int bar ){ return bar * 100; }
}
// hosting the service within your application
var baseUri = new Uri( "net.tcp://localhost:59999/" );
var serviceHost = new ServiceHost( typeof( MyService ), baseUri );
// many options can/should be set here, e.g. throttling, security, and serialization behavior
var binding = new NetTcpBinding();
var endpoint = serviceHost.AddServiceEndpoint( typeof( IMyService ), binding, baseUri );
This is all you need for a caller to interface with an existing instance of the application, but it doesn't address the need to ensure that the app is running.
Step 2
A wrapper class may make it easier to locate/launch your application.
public sealed class MyWrapper
{
public IMyService GetService()
{
// TODO: perform appropriate OS-wide locking here
// TODO: see if app is running
// TODO: if not, launch it in a new process
// create a channel to connect the WCF endpoint we just defined
var channel = GetChannel();
// TODO: release lock
// return the channel to the caller
return channel;
}
public GetChannel( Binding binding, EndpointAddress endpointAddress )
{
var channelFactory = new ChannelFactory<IMyService>( binding, endpointAddress );
return _channelFactory.CreateChannel();
}
}
Step 3
Your callers can connect to your application from anywhere on the machine (or beyond, if you wish):
var wrapper = new Wrapper();
var service = wrapper.GetService();
int result = service.Foo( 123 );
While a bit unusual, your service code could also manipulate the GUI. For example:
var wrapper = new Wrapper();
var service = wrapper.GetService();
// call a method, the implementation of which launches a "contact form"
// with data preloaded for the specified contact ID
service.ShowContactForm( 1 );
Cleanup
Note that this syntax I've shown so far is elegant, but it doesn't handle closing the channel or channel factory. There are a variety of ways to do this; I've used a pattern like this:
public sealed class ServiceClient
{
private readonly ChannelFactory<IMyService> _channelFactory;
public ServiceClient( Binding binding, EndpointAddress endpointAddress )
{
_channelFactory = new ChannelFactory<IMyService>( binding, endpointAddress );
Channel = _channelFactory.CreateChannel();
}
public IMyService Channel { get; private set; }
public void Dispose()
{
if( Channel != null )
{
// TODO: check the state of the channel and close/abort appropriately
}
if( _channelFactory != null )
{
_channelFactory.Close();
}
}
}
public sealed class MyWrapper
{
public ServiceClient GetClient()
{
// Similar setup to the previous example, except the service client wraps
// the channel factory.
}
}
var wrapper = new Wrapper();
using( var client = wrapper.GetClient() )
{
client.Channel.Foo( 123 );
}
It's a bit more verbose, but it gives you much more control over cleanup and any other options you wish to control.
Solution Structure
All of this code can potentially live in one assembly. However, it may be cleaner to place the wrapper in a separate assembly and the service contract(s) interfaces into another assembly referenced by the wrapper and the main application.
Assembly 1: service contracts (interfaces)
Assembly 2: GUI application, references assembly 1 and implements its service contracts
Assembly 3: wrapper class, references assembly 1

Parallelize / Multi-Thread a singleton object method call

Code Details:
// Singleton class CollectionObject
public class CollectionObject
{
private static CollectionObject instance = null;
// GetInstance() is not called from multiple threads
public static CollectionObject GetInstance()
{
if (CollectionObject.instance == null)
CollectionObject.instance = new CollectionObject();
return CollectionObject.instance;
}
// Dictionary object contains Service ID (int) as key and Service object as the value
// Dictionary is filled up during initiation, before the method call ReadServiceMatrix detailed underneath
public Dictionary<int, Service> serviceCollectionDictionary = new Dictionary<int,Service>();
public Service GetServiceByIDFromDictionary(int servID)
{
if (this.serviceCollectionDictionary.ContainsKey(servID))
return this.serviceCollectionDictionary[servID];
else
return null;
}
}
DataTable serviceMatrix = new DataTable();
// Fill serviceMatrix data table from the database
private int ReadServiceMatrix()
{
// Access the Singleton class object
CollectionObject collectionObject = CollectionObject.GetInstance();
// Parallel processing of the data table rows
Parallel.ForEach<DataRow>(serviceMatrix.AsEnumerable(), row =>
{
//Access Service ID from the Data table
string servIDStr = row["ServID"].ToString().Trim();
// Access other column details for each row of the data table
string currLocIDStr = row["CurrLocId"].ToString().Trim();
string CurrLocLoadFlagStr = row["CurrLocLoadFlag"].ToString().Trim();
string nextLocIDStr = row["NextLocId"].ToString().Trim();
string nextLocBreakFlagStr = row["NextLocBreakFlag"].ToString().Trim();
string seqStr = row["Seq"].ToString().Trim();
int servID = Int32.Parse(servIDStr);
int currLocID = Int32.Parse(currLocIDStr);
int nextLocID = Int32.Parse(nextLocIDStr);
bool nextLocBreakFlag = Int32.Parse(nextLocBreakFlagStr) > 0 ? true : false;
bool currLocBreakFlag = Int32.Parse(CurrLocLoadFlagStr) > 0 ? true : false;
int seq = Int32.Parse(seqStr);
// Method call leading to the issue (definition in Collection Object class)
// Fetch service object using the Service ID from the DB
Service service = collectionObject.GetServiceByIDFromDictionary(servID);
// Call a Service class method
service.InitLanes.Add(new Service.LaneNode(currLoc.SequentialID, currLocBreakFlag, nextLoc.SequentialID, nextLocBreakFlag, seq));
}
Issue that happens is:
In the code above for all the Service objects in the dictionary, the subsequent method call is not made, leading to issues in further processing. It has to o with fetching the Service object from the dictionary in parallel mode
The db an dictionary contains all the Ids /Service objects, but my understanding is when processing in Parallel mode for the Singleton class, few of the objects are skipped leading to the issue.
In my understanding the service id passed and service object created is local to a thread, so there shouldn't be an issue that I am facing. This kind of issue is only possible, when for a given method call one thread replace service id value of another thread by its, thus both end up with Service object and few are thus skipped, which is strange in my view until and unless I do not understand the Multi threading in this case correctly
Currently I am able to run the same code in non threaded mode by using the foreach loop instead of Parallel.ForEach / Parallel.Invoke
Please review and let me know your view or any pointer that can help me resolve the issue
In my understanding the service id passed and service object created
is local to a thread
Your understanding is incorrect, if two threads request the same service id the two threads will be both working on the same singular object. If you wanted separate objects you would need to put some kind of new Service() call in GetServiceByIDFromDictionary instead of a dictionary of existing values.
Because multiple threads could be using the same service objects I think your problem lies from the fact that service.InitLanes.Add is likely not thread safe.
The easiest fix is to just lock on that single step
//...SNIP...
Service service = collectionObject.GetServiceByIDFromDictionary(servID);
// Call a Service class method, only let one thread do it for this specific service instance,
// other threads locking on other instances will not block, only other threads using the same instance will block
lock(service)
{
service.InitLanes.Add(new Service.LaneNode(currLoc.SequentialID, currLocBreakFlag, nextLoc.SequentialID, nextLocBreakFlag, seq));
}
}
This assumes that this Parallel.Foreach is the only location collectionObject.GetServiceByIDFromDictionary is used concurrently. If it is not, any other locations that could potentially be calling any methods on returned services must also lock on service.
However if Service is under your control and you can somehow modify service.InitLanes.Add to be thread safe (perhaps change InitLanes out with a thread safe collection from the System.Collections.Concurrent namespace) that would be a better solution than locking.
1.Implementing singleton always think about using of it in mulithreaded way. Always use multithreaded singleton pattern variant, one of them - lazy singleton. Use Lazy singleton using System.Lazy with appropriate LazyThreadSafeMode consturctor argument:
public class LazySingleton3
{
// static holder for instance, need to use lambda to enter code here
//construct since constructor private
private static readonly Lazy<LazySingleton3> _instance
= new Lazy<LazySingleton3>(() => new LazySingleton3(),
LazyThreadSafeMode.PublicationOnly);
// private to prevent direct instantiation.
private LazySingleton3()
{
}
// accessor for instance
public static LazySingleton3 Instance
{
get
{
return _instance.Value;
}
}
}
Read about it here
2.Use lock-ing of your service variable in parallel loop body
// Method call leading to the issue (definition in Collection Object class)
// Fetch service object using the Service ID from the DB
Service service = collectionObject.GetServiceByIDFromDictionary(servID);
lock (service)
{
// Call a Service class method
service.InitLanes.Add(new Service.LaneNode(currLoc.SequentialID,
currLocBreakFlag, nextLoc.SequentialID,
nextLocBreakFlag, seq));
}
3.Consider to use multithreading here. Using lock-ing code make your code not so perfomant as synchronous. So make sure you multithreaded/paralelised code gives you advantages
4.Use appropriate concurrent collections instead of reinventing wheel - System.Collections.Concurrent Namespace

Categories