I'm trying to execute a method from an object which is loaded from an assembly that is dynamically generated with CompilerResults.CompiledAssembly. However, I need this assembly to have restricted permissions because the methods it contains have an unexpected behavior.
I've searched a lot and the Microsoft docs suggest to use the security features provided by .NET Framework 4. This is one of the many sources I've read about sandboxing, which uses a different AppDomain with restricted permissions. Theoretically, I can create instances from the class within the assembly that is loaded in the restricted AppDomain and this instance will be considered a remote object.
To use the new object as a reference, a proxy is created internally when you try to access the object if the class extends the MarshalByRefObject class. In my case, the class which extends MarshalByRefObject is at the top of the hierarchy.
A simplified version of the code based on the link I've mentioned before is:
var permissionSet = ...;
var dllPath = ...;
// Create the AppDomainSetup
var info = new AppDomainSetup
{
// Set the path to the assembly to load.
ApplicationBase = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)
};
var strongName = assembly.Evidence.GetHostEvidence<StrongName>();
// Create the domain
var sandboxDomain = AppDomain.CreateDomain("RestrictedDomain", null, info, permissionSet, new StrongName[] { strongName });
var handle = Activator.CreateInstanceFrom(sandboxDomain, dllPath, "MyNamespace.MyClass");
var myLoadedTypeInstance = handle.Unwrap() as MyClass;
The code above works, the assembly is loaded in the AppDomain (only can do it referencing it's dll location, not it's name). But when I try to use a method from myLoadedTypeInstance with two serializable parameters I get an exception. The call is something like myLoadedTypeInstance.MyMethod(param1, param2) and the exception is:
"Method InitializeLifetimeService is not supported on this proxy, this can happen if the method is not marked with OperationContractAttribute or if the interface type is not marked with ServiceContractAttribute."
Some details:
I don't know if it matters, but the first parameter is an objects which contains a property of type TChannel, created with ChannelFactory<T>.CreateChannel().
It confuses me that the code fails when initializing lifetime service, but if I use RemotingServices.GetLifetimeService(myLoadedTypeInstance) as ILease I can access all the remote object's lifetime info.
I've also tried to treat it as a remote object explicitly using Activator.GetObject() with the URL provided by RemotingServices.GetObjectUri(myLoadedTypeInstance), which is redundant because I end up creating two instances of the object. But it was a desperate move which had the same ending.
I cannot debug this with VisualStudio as it's running in a separate process.
Related
maybe someone can help me out with this one:
I'm writing a Program, that dynamically loads assemblies that have different implementations of the same interface "IMyService".
The case may occur, that some of the assemblies aren't even there (imagine this as a set of different modules of a software a user can buy... Some are bought, some aint, therefore the functionality isn't available and the dll isn't delivered).
So what I'm trying to do is the following:
private IServiceProvider ConfigureServices()
{
const string vendor = "MyVendor";
var assembly = Assembly.LoadFrom($"{vendor}.dll");
var myVendorType = assembly.GetType($"{vendor}.Services.{vendor}Service");
if (myVendorType == null)
throw new Exception($"Module '{vendor}' not found");
var services = new ServiceCollection();
// ... other services
serviceCollection.TryAddSingleton<IMyService, myVendorType>();
return serviceCollection.BuildServiceProvider();
}
Unfortunately this won't compile, since the IDE is telling me that it can't resolve the Symbol "myVendorType", when the Type is provided as the Implementation of the "TryAddSingleton..."
I know that the creation of an instance needs an Activator like so:
Activator.CreateInstance(myVendorType);
but, I have no idea what to do, when I want to provide the type to implement to the Service-Collection.
I hope someone has an idea :)
As I mentioned in the comment you could register instance directly in service collection.
For that you could do services.TryAddSingleton<IMyService>(sp => (IMyService)Activator.CreateInstance(myVendorType))
Or even just services.TryAddSingleton<IMyService>( (IMyService)Activator.CreateInstance(myVendorType))
The first option is useful when you need to get something other from ServiceProvider to correctly instantiate the needed instance
Having a heck of a time figuring out how to get Autofac to load plugins. I'm new to Autofac.
I have plugins like ServiceA.dll, ServiceB.dll, etc. When configuring my Autofac container I scan the current directory for Service*.dll and pull the name of the service "A", "B", out of the filename and store in a variable named serviceName. Then I find the type of the service class that implements IService and put it in a variable named serviceType. Each service also has a config setting class named <serviceName>Settings so I find that class and put its type in a variable named serviceSettingsType. Then register:
builder.RegisterType(serviceType)
.Named<IService>(serviceName);
builder.RegisterType(serviceSettingsType)
.Named<IServiceSettings>(serviceName+"Settings")
After building the Autofac config, I can get a service type like so:
scope.ResolveNamed<IService>("A");
And presto, the class ServiceA is instantiated. However, ServiceA takes a ctor param:
public class ServiceA(ServiceASettings settings) {}
Autofac instantiates a ServiceASettings class just fine (it's just a "data class" with one or more properties) and passes that into the ctor of ServiceA.
What I can't figure out is how to tell Autofac that to create a ServiceASettings class to pass into the ServiceA ctor it needs to instantiate a SettingsManager class and then call var settings = await Task<T> ReadFromFile(string settingsFilename) (where T is the type of the ASettings class) and use that settings class in ServiceA's ctor call. Just like the service name above ("A" in the example) is determined from the command line, the settingsFilename passed to the ReadFromFileAsync needs to be passed in at runtime.
Hope this makes sense. I feel like I'm very close to loading plugins with Autofac but just can't figure out the proper factory calls or named parameter calls for the Service ctor. Anyone done something similar to this with Autofac? Suggestions for changing the architecture of my plugin classes and/or SettingsManager class are also more than welcome if it helps make this work easier with Autofac.
EDIT:
Got this to work. I re-read the page #cynic pointed to and the syntax runtime parameters finally clicked for me.
Changed my SettingsManager class to one called SettingsFile that takes a Type, an IFileSystem, and a string with the filename and exposes a ReadSettings method. Register:
builder.Register((c, p) => new SettingsFile(
c.Resolve<IFileSystem>(),
p.Named<Type>("settingsType"),
p.Named<string>("settingsFilename")))
.As<ISettingsFile>();
Resolve:
var settingsName = "Service1Settigns";
var settingsType = scope.ResolveNamed<ISettings>(settingsName);
var settingsFile = scope.Resolve<ISettingsFile>(
new NamedParameter("settingsType", settingsType.GetType()),
new NamedParameter("settingsFilename", settingsFilename));
var settings = settingsFile.ReadSettings();
(I think there's a way to get the resolver to call ReadSettings for me, but haven't figured that out yet. But I'll probably want to trap errors and enhance with very specific error messages anyhow.)
Then while scanning the plugin DLLs the various classes are registered like so:
var assemblyTypes = assembly.GetTypes();
var settingsTypes = FindType(assemblyTypes, typeof(ISettings));
var settingsType = settingsTypes.First();
builder.RegisterType(settingsType).Named<ISettings>(settingsName);
Similar registering is done for IService and IRepository and here's how a client is fired up:
var client = scope.ResolveNamed<IClient>(clientName,
new NamedParameter("settings", settings),
new NamedParameter("repository", repository));
This gives me an IClient based on the clientName which in this case is specified on the command line (as is the appropriate settings file path to use for this client).
Getting to really like the features of Autofac!
I'm using
VS2013 MVC5,
SimpleInjector 2.4.1
MvcSiteMapProvider.MVC5.DI.SimpleInjector.Modules 4.4.10
and I'm getting the following error when calling 'Verify' on the container
Additional information: The configuration is invalid. Creating the instance for type IAttributeAssemblyProvider failed. The registered delegate for type IAttributeAssemblyProvider threw an exception. The constructor of the type AttributeAssemblyProvider contains the parameter of type IEnumerable<String> with name 'includeAssemblies' that is not registered. Please ensure IEnumerable<String> is registered in the container, or change the constructor of AttributeAssemblyProvider.
The array it is referencing is :
string[] includeAssembliesForScan = new string[] { "MyProject" };
and this is what seems to be the culprit :
container.RegisterSingle<ReflectionSiteMapNodeProvider>(() =>
container.GetInstance<ReflectionSiteMapNodeProviderFactory>()
.Create(includeAssembliesForScan));
The signature for the create method is :
public MvcSiteMapProvider.Builder.ReflectionSiteMapNodeProvider Create(System.Collections.Generic.IEnumerable<string> includeAssemblies)
Member of MvcSiteMapProvider.Builder.ReflectionSiteMapNodeProviderFactory
I think the IAttributeAssemblyProvider is being registered as per below
// Single implementations of interface with matching name (minus the "I").
CommonConventions.RegisterDefaultConventions(
(interfaceType, implementationType) => container.RegisterSingle(interfaceType, implementationType),
new Assembly[] { siteMapProviderAssembly },
allAssemblies,
excludeTypes,
string.Empty);
since :
public class AttributeAssemblyProvider : IAttributeAssemblyProvider
and the ctor is :
public AttributeAssemblyProvider(
IEnumerable<string> includeAssemblies,
IEnumerable<string> excludeAssemblies)
{...}
Thanks in advance for any help
stack trace is :
at SimpleInjector.InstanceProducer.VerifyExpressionBuilding() at
SimpleInjector.Container.VerifyIfAllExpressionsCanBeBuilt(InstanceProducer[]
producersToVerify) at
SimpleInjector.Container.VerifyIfAllExpressionsCanBeBuilt() at
SimpleInjector.Container.Verify() at
MyProject.App_Start.SimpleInjectorInitializer.Intialise() in
\App_Start\SimpleInjectorInitializer.cs:line 54 at
MyProject.MvcApplication.Application_Start() in \Global.asax.cs:line
16
The latest versions of the external DI config files don't automatically update when you upgrade if you have changed them. Be sure you have merged in the latest versions of CommonConventions.cs and MvcSiteMapProviderContainerInitializer.cs from the master branch (this is to be done manually, but it helps a lot if you use a diff tool to quickly see the changes). You can also view the releases list to see the various points where updates were done to the DI configuration with direct links to the diff on GitHub.
The latest version of CommonConventions.RegisterDefaultConventions excludes auto-registration of any types that have a string parameter in the constructor (which AttributeAssemblyProvider does), so be sure you have merged the latest changes of that file into your project.
Of course, if all else fails you can add typeof(AttributeAssemblyProvider) to the excludeTypes array and it will no longer be auto-registered. It is not supposed to be because it has a factory class that instantiates it named AttributeAssemblyProviderFactory.
Also, if you are not using MvcSiteMapNodeAttribute to register nodes, it is not necessary to have it in your configuration at all. Removing it will make your SiteMap load a little faster.
To remove it, change this...
container.RegisterSingle<ReflectionSiteMapNodeProvider>(() => container.GetInstance<ReflectionSiteMapNodeProviderFactory>()
.Create(includeAssembliesForScan));
// Register the sitemap builders
container.RegisterSingle<ISiteMapBuilder>(() => container.GetInstance<SiteMapBuilderFactory>()
.Create(new CompositeSiteMapNodeProvider(container.GetInstance<XmlSiteMapNodeProvider>(), container.GetInstance<ReflectionSiteMapNodeProvider>())));
To this...
// Register the sitemap builders
container.RegisterSingle<ISiteMapBuilder>(() => container.GetInstance<SiteMapBuilderFactory>()
.Create(container.GetInstance<XmlSiteMapNodeProvider>()));
This is exactly what the "MvcSiteMapProvider_ScanAssembliesForSiteMapNodes" web.config setting does when set to "false" when you are using the internal DI container.
We have 2 orgs running in our on-premise crm 2011 system.
We have generated early bound classes for both orgs.
One of our plugins is throwing the "a proxy type with the name account has been defined by another assembly" error when deactivating an account.
That plugin only references one of the early bound dll's.
How do I get the CRM system to respect the namespace of these references.
I've tried the few items that show up from Google and none are working.
Since you can reproduce this with 2 vanilla orgs I would imaging there is something OUTSIDE the code layer we can do without having to go back and refactor a bunch of code for the 2 orgs.
Thanks,
Jon
The problem is actually with WCF attempting to deserialize the server response and not being able to identify the correct type. The best method to sort this issue is to pass in the current assembly using Assembly.GetExecutingAssembly() to the ProxyTypesBehavior() while creating the proxy like so.
using (serviceProxy = new OrganizationServiceProxy(config.OrganizationUri,
config.HomeRealmUri,
config.Credentials,
config.DeviceCredentials))
{
// This statement is required to enable early-bound type support.
serviceProxy.ServiceConfiguration.CurrentServiceEndpoint.Behaviors.Add(new ProxyTypesBehavior(Assembly.GetExecutingAssembly()));
}
You may run into this issue when referencing different assemblies containing proxy-classes, i.e. one assembly wrapping the server SDK (Microsoft.Xrm.Sdk) and another assembly wrapping the client SDK (Microsoft.Xrm.Sdk.Client).
In such a scenario it seems to be required to tell the OrganizationServiceProxy which assembly should be used to resolve the proxy classes.
This should help:
var credentials = new ClientCredentials();
credentials.Windows.ClientCredential = new System.Net.NetworkCredential(userName, password, domain);
var proxy = new OrganizationServiceProxy(new Uri(discoveryUrl), null, credentials, null);
proxy.EnableProxyTypes(typeof(CrmServiceContext).Assembly);
var context = CrmServiceContext(proxy);
The important thing is to call EnableProxyTypes by passing the correct assembly. I saw another solution using CrmConnection but CrmConnection is only available in the client SDK, which means that you can't instantiate a "server-OrganizationServiceProxy" this way. EnableProxyTypes(Assembly assembly) works for both sides.
Hope this helps.
Regards,
MH
It maybe years since this question has been raised. However, I faced this problem recently and have been extremely worried about thousands of lines of code to be changed. However, I was lucky to find the following simple change to get myself out of hell:
Suppose there are two context objects you deal with:
an OrganizationServiceContext object: context1
a CrmSvcUtil Context object: context2
and a single OrganizationServiceProxy object: service
if in a single method, you make multiple CRUD operations using the same service object but with either of context objects as exemplified above, it is highly probable that this error be raised. However, by doing the following, you can prevent it to happen.
Every time you want to work with context1, you precede the context object with the service object as following:
service.EnableProxyTypes(typeof(OrganizationServiceContext).Assembly);
using (var context1 = new OrganizationServiceContext(_service)){
// your classic code here
}
Also, every time you want to work with context2, you follow the same structure:
service.EnableProxyTypes(typeof(HiwebContext).Assembly);
using (var context = new XYZContext(this._service)){
// your CrmSvcUtil none-classic code here
}
this normally means that there is one or more assemblies with the same method name or property to fix this use the fully qualified name of the assembly.. for example in the using System.IO for example if you had a method named the same way in your Class code that conflicts with System.IO.... you would write your fix like
thisObject.System.IO.Path( ---- ) = somthing for example.. does this make sense..?
I found that adding the Assembly.GetExecutingAssembly() solved the problem.
adding the Assembly.GetExecutingAssembly() solve my problem, you also need to add using System.Reflection;
thanks
I'm writing an application which needs to host several WCF services. One of the strengths of WCF is the ability to configure services without having to recompile, by specifying settings in the app.config file.
When self-hosting, there does not appear to be an out-of-the-box way to automatically host services which are in the app.config file. I found this question which mentions a possible solution of dynamically enumerating services listed in app.config at runtime, and creating a ServiceHost for each.
However, my services, contracts, and the hosting application are all in different assemblies. This causes Type.GetType(string name) to fails to locate my service type (returns null) because it is defined in a different assembly.
How can I reliably host all services listed in the app.config file dynamically (i.e., without hard-coding new ServiceHost(typeof(MyService)) in my self-hosting application?
Note: My app.config was generated using the "WCF Configuration Editor" in Visual Studio 2010.
Note also: My primary goal is to have this driven by the app.config file so there is a single point of configuration. I don't want to have to configure this in a separate location.
EDIT: I am able to read the app.config file (see here), but need to be able to resolve types in different assemblies.
EDIT: One of the answers below prompted me to try specifying the AssemblyQualifiedName in app.config instead of just the basic type name. This was able to get around the Type.GetType() problem, however ServiceHost.Open() now fails with an InvalidOperationException regardless of how I attain the type:
// Fails
string typeName = typeof(MyService).AssemblyQualifiedName;
Type myType = Type.GetType(typeName);
ServiceHost host = new ServiceHost(myType);
host.Open(); // throws InvalidOperationException
// Also fails
Type myType2 = typeof(MyService);
ServiceHost host2 = new ServiceHost(myType2);
host2.Open(); // throws InvalidOperationException
Exception details:
Service 'SO.Example.MyService' has zero application (non-infrastructure) endpoints. This might be because no configuration file was found for your application, or because no service element matching the service name could be found in the configuration file, or because no endpoints were defined in the service element.
I guess WCF attempts to match the literal string for the service name when parsing the app.config file internally.
EDIT/ANSWER: What I ended up doing was basically what was in the answer below. Instead of using Type.GetType() I know that all of my services are in the same assembly, so I switched to:
// Get a reference to the assembly which contain all of the service implementations.
Assembly implementationAssembly = Assembly.GetAssembly(typeof(MyService));
...
// When loading the type for the service, load it from the implementing assembly.
Type implementation = implementationAssembly.GetType(serviceElement.Name);
// get the <system.serviceModel> / <services> config section
ServicesSection services = ConfigurationManager.GetSection("system.serviceModel/services") as ServicesSection;
// get all classs
var allTypes = AppDomain.CurrentDomain.GetAssemblies().ToList().SelectMany(s => s.GetTypes()).Where(t => t.IsClass == true);
// enumerate over each <service> node
foreach (ServiceElement service in services.Services)
{
Type serviceType = allTypes.SingleOrDefault(t => t.FullName == service.Name);
if (serviceType == null)
{
continue;
}
ServiceHost serviceHost = new ServiceHost(serviceType);
serviceHost.Open();
}
Based on the other answers, I extended the code to the following, which searches all assemblies for the services in the app.config
That should definitely be possible ! Check out this code fragment - use it as a foundation and go from here:
using System.Configuration; // don't forget to add a reference to this assembly!
// get the <system.serviceModel> / <services> config section
ServicesSection services = ConfigurationManager.GetSection("system.serviceModel/services") as ServicesSection;
// enumerate over each <service> node
foreach(ServiceElement aService in services.Services)
{
Console.WriteLine();
Console.WriteLine("Name: {0} / Behavior: {1}", aService.Name, aService.BehaviorConfiguration);
// enumerate over all endpoints for that service
foreach (ServiceEndpointElement see in aService.Endpoints)
{
Console.WriteLine("\tEndpoint: Address = {0} / Binding = {1} / Contract = {2}", see.Address, see.Binding, see.Contract);
}
}
This right now just prints out the info - but you could definitely use this to actually build up your service hosts inside your own NT service !
Update: ok, sorry, I missed your most important point - the fact the actual services are in different assemblies.
In that case, you need to dynamically load those assemblies, as needed - you could e.g. "just simply know" what assemblies to load, or you could put them all into a specific subdirectories and load all assemblies in that directory, or you could just inspect all assemblies in the same location where your MyOwnServiceHost.exe resides and check if you find any types that you need.
This part - which service type to find in which assembly - isn't handled by WCF configuration - you need to do this yourself, by whichever means makes most sense to you.
// find currently executing assembly
Assembly curr = Assembly.GetExecutingAssembly();
// get the directory where this app is running in
string currentLocation = Path.GetDirectoryName(curr.Location);
// find all assemblies inside that directory
string[] assemblies = Directory.GetFiles(currentLocation, "*.dll");
// enumerate over those assemblies
foreach (string assemblyName in assemblies)
{
// load assembly just for inspection
Assembly assemblyToInspect = Assembly.ReflectionOnlyLoadFrom(assemblyName);
if (assemblyToInspect != null)
{
// find all types
Type[] types = assemblyToInspect.GetTypes();
// enumerate types and determine if this assembly contains any types of interest
// you could e.g. put a "marker" interface on those (service implementation)
// types of interest, or you could use a specific naming convention (all types
// like "SomeThingOrAnotherService" - ending in "Service" - are your services)
// or some kind of a lookup table (e.g. the list of types you need to find from
// parsing the app.config file)
foreach(Type ty in types)
{
// do something here
}
}
}
You correctly identified the answer to your problem in your question link and #marc_s answer also gives the correct approach too. The actual issue you are having is that you need to dynamically get the Type instance of an assembly that may only be referenced through a config file so it may not be loaded into the current AppDomain.
Look at this blog post for a way to dynamically reference assemblies in your code. Although the post is specifically for an ASP.NET application, the general approach should work in a self hosted scenario. The ideas is to replace the Type.GetType(string) call with a private method call that dynamically loads the requested assembly (if needed) and returns the Type object. The parameter you send this method will still be the element.Name and you'll need to figure out which is the correct assembly to load. A simple convention-based assembly naming scheme should work. For example, if service type is:
MyNamespace.MyService.MyServiceImpl
then assume the assembly is:
MyNamespace.MyService