I am programming an application in visual studio 2010 and i want to add a library to references using c# ,so i will add the using library and the invocation in file of a business class
public void addreference()
{
//needed code
}
public addInvocation()
{
//write in the file of business class
}
it is like select add reference using the mouse but i am wishing use c# to do it
how can i do it ?
Critical solution
i tried to use the solution but i found a problem , i instantiated successfully the class of the library but i can not use their methods
first i created an Interface called Interface1
second i created a class called Classe1
then I generated the .dll
The code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ClassLibrary1
{
public interface Interface1
{
int add();
int sub();
}
public class Class1 : Interface1
{
Class1()
{
}
#region Interface1 Members
public int add()
{
return 10;
}
public int sub()
{
return -10;
}
#endregion
}
}
the i tied to instantiate the class1
the code
string relative = "ClassLibrary1.dll";
string absolute = Path.GetFullPath(relative);
Assembly assembly = Assembly.LoadFile(absolute);
System.Type assemblytype = assembly.GetType("ClassLibrary1.Class1");
object a = assembly.CreateInstance("ClassLibrary1.Class1", false, BindingFlags.CreateInstance, null,null,null, null);
Now i wish invoke the method add how can i do it
var a = Activator.CreateInstance(assemblytype, argtoppass);
System.Type type = a.GetType();
if (type != null)
{
string methodName = "methodname";
MethodInfo methodInfo = type.GetMethod(methodName);
object resultpath = methodInfo.Invoke(a, argtoppass);
res = (string)resultpath;
}
Reflection seems the obvious option. Start with
foreach (FileInfo dllFile in exeLocation.GetFiles("*.dll"))
{
Assembly assembly = Assembly.LoadFile(dllFile.FullName);
...
then:
Type[] exportedTypes = assembly.GetExportedTypes();
foreach (Type exportedType in exportedTypes)
{
//look at each instantiable class in the assembly
if (!exportedType.IsClass || exportedType.IsAbstract)
{
continue;
}
//get the interfaces implemented by this class
Type[] interfaces = exportedType.GetInterfaces();
foreach (Type interfaceType in interfaces)
{
//if it implements IMyPlugInterface then we want it
if (interfaceType == typeof(IMyPlugInterface))
{
concretePlugIn = exportedType;
break;
}
}
finally
IMyPlugInterface myPlugInterface = (IMyPlugInterface) Activator.CreateInstance(concretePlugIn);
...or something like that. It won't compile but yet get the jist.
Related
I have a logger that records the method name (which I get through reflection) and parameters (which are manually passed to the logger). Here's an example of the proper way to do the logging:
public void Foo() {
// This is correct - the method has no parameters, neither does the logging
Logger.Log();
// Method
}
public void Foo1(int a, int b) {
// Log both of the parameters correctly
Logger.Log(a, b);
// Rest of method
}
However, people will periodically call this incorrectly. For example:
public void Foo1(int a, int b) {
// Didn't record any of the parameters
Logger.Log();
// Rest of method
}
or
public void Foo1(int a, int b, int c) {
// Someone changed the number of parameters but didn't update the logging call
Logger.Log(a, b);
}
The signature of the Log method is:
public void Log(params object[] parameters)
I'd like to have some way of requiring that Logger.Log have the same number of parameters as the method calling it does.
I know how to do this at runtime (just use reflection to get the parameter list for the caller and compare it to what parameters I actually received), but that would be a really bad solution to this I think since the vast majority of the checks would be unnecessary. (It would also mean that you wouldn't know until runtime that you had written it incorrectly, and then only if you happened to execute that particular method).
Right now we're not using FxCop unfortunately (or I'd just write some kind of rule) and I suspect that I wouldn't succeed in changing that fact. Short of writing a compiler plugin of some kind, is there a way to force people to use this method correctly?
You should be able to accomplish this using the new Roslyn API's. You'll want to install the SDK here:
https://marketplace.visualstudio.com/items?itemName=VisualStudioProductTeam.NETCompilerPlatformSDK
Once installed you should go to new project and navigate to Extensibility and you'll see the project type Analyzer with Code Fix (NuGet + VSIX) template. I created a sample project that I used to show the compiler errors:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AnalyzerTest
{
public static class Logger
{
public static void Log(params object[] parameters)
{
}
}
}
namespace AnalyzerTest
{
public class Foo
{
public void Foo1(int a, int b)
{
// Didn't record any of the parameters
Logger.Log();
// Rest of method
}
}
}
I created a separate project for the analyzer and here is the code for the analyzer class:
using System;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Semantics;
namespace Analyzer1
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class LoggerAnalyzer : DiagnosticAnalyzer
{
public const string DiagnosticId = "Logging";
internal const string Title = "Logging error";
internal const string MessageFormat = "Logging error {0}";
internal const string Description = "You should have the same amount of arguments in the logger as you do in the method.";
internal const string Category = "Syntax";
internal static DiagnosticDescriptor Rule =
new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat,
Category, DiagnosticSeverity.Error, isEnabledByDefault: true, description: Description);
public override ImmutableArray<DiagnosticDescriptor>
SupportedDiagnostics
{ get { return ImmutableArray.Create(Rule); } }
public override void Initialize(AnalysisContext context)
{
context.RegisterSyntaxNodeAction(
AnalyzeNode, SyntaxKind.InvocationExpression);
}
private void AnalyzeNode(SyntaxNodeAnalysisContext context)
{
var invocationExpr = (InvocationExpressionSyntax)context.Node;
var memberAccessExpr = invocationExpr.Expression as MemberAccessExpressionSyntax;
if (memberAccessExpr != null && memberAccessExpr.Name.ToString() != "Log")
{
return;
}
var memberSymbol =
context.SemanticModel.GetSymbolInfo(memberAccessExpr).Symbol as IMethodSymbol;
if (memberSymbol == null || !memberSymbol.ToString().StartsWith("AnalyzerTest.Logger.Log"))
{
return;
}
MethodDeclarationSyntax parent = GetParentMethod(context.Node);
if(parent == null)
{
return;
}
var argumentList = invocationExpr.ArgumentList;
Int32 parentArgCount = parent.ParameterList.Parameters.Count;
Int32 argCount = argumentList != null ? argumentList.Arguments.Count : 0;
if (parentArgCount != argCount)
{
var diagnostic = Diagnostic.Create(Rule, invocationExpr.GetLocation(), Description);
context.ReportDiagnostic(diagnostic);
}
}
private MethodDeclarationSyntax GetParentMethod(SyntaxNode node)
{
var parent = node.Parent as MethodDeclarationSyntax;
if(parent == null)
{
return GetParentMethod(node.Parent);
}
return parent;
}
}
}
While in the Analyzer with Code Fix project you can hit F5 (as long as your .Vsix project is the startup project) and it will open up another VS instance and you can choose the project you would like to test the analyzer on.
Here is the result:
It also looks like you will have to install this as a NuGet package instead of a VS Extension, for whatever reason VS Extensions don't affect the build and you will only get the warning:
https://stackoverflow.com/a/39657967/1721372
For a more complete example see here:
https://msdn.microsoft.com/en-us/magazine/dn879356.aspx
I am trying to make a (my first MEF) system in which plugins can be recursive, i.e. my main system calls a MEF plugin with a standard interface, which on its own can then call another (or several) plugin(s), and so on.
When testing though, my plugin does not call the underlying plugin, but starts processing itself (creating a loop).
Any idea how I can prevent this?
Interface:
public interface IConnector
{
XDocument Run(object serviceCredentials, object connectorIds, object connectorKeys);
}
My main plugin inherits the interface, and defines the import for the next (The subplugin has the same definition):
[Export(typeof(IConnector))]
public class Connector : IConnector
{
[Import(typeof(IConnector))]
private IConnector connector;
....
The called plugin is initiated (in the Run method of the main plugin):
public XDocument Run(object serviceCredentials, object connectorIds, object connectorKeys)
{
string calledConnector = Path.Combine(AssemblyDirectory, "subplugin.dll");
AssemblyCatalog assembyCatalog = new AssemblyCatalog(Assembly.LoadFrom(calledConnector));
CompositionContainer container = new CompositionContainer(assembyCatalog);
container.ComposeParts(this);
....
The container should now contain just one plugin, the subplugin.dll.
I call the method 'Run' which is in the interface to invoke the subplugin method:
XDocument something = connector.Run(serviceCredentials, connectorids, connectorkeys);
But, instead of running the subplugin code, the 'Run' method in my main plugin activates, which keeps activating itself.
When I remove the [Export(typeof(iConnector)] in the main plugin, the subplugin is activated, but I want my main plugin to be able to be called in the same manner.
Being new to MEF I am stuck as to how to solve this. Any help would be much appreciated!
You should use Contracts and specify your intent, otherwise MEF will go into an infinite loop or pick the Connector as it exposes IConnector itself.
Some more info from MSDN.
For example
[Export("Container", typeof(IConnector))]
public class Connector : IConnector
{
[Import("Component", typeof(IConnector))]
private IConnector connector;
....
UPDATE
So after giving it some thought, here is an example of metadata based approach, and one that also limits the number of expensive catalog operations.
The IConnector
using System.Xml.Linq;
namespace Common
{
public interface IConnector
{
XDocument Run(object serviceCredentials, object connectorIds, object connectorKeys);
void Identify();
}
}
The metadata attribute ConnectorMetadata
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
namespace Common
{
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class)]
public class ConnectorMetadata : ExportAttribute
{
public string Name { get; private set; }
public ConnectorMetadata(string name):base(typeof(IConnector))
{
Name = name;
}
public ConnectorMetadata(IDictionary<string, object> metaData) : base(typeof (IConnector))
{
Name = Convert.ToString(metaData["Name"]);
}
}
}
The lazy singleton for PluginsCatalog
using System;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.IO;
using System.Linq;
using System.Reflection;
using Common;
namespace Common
{
public class PluginsCatalog
{
[ImportMany]
public Lazy<IConnector, ConnectorMetadata>[] Connectors;
private static readonly Lazy<PluginsCatalog> LazyInstance = new Lazy<PluginsCatalog>(() => new PluginsCatalog());
private PluginsCatalog()
{
var assemblyCatalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
var path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? Directory.GetCurrentDirectory();
var directoryCatalog = new DirectoryCatalog(path, "*plugin.dll");
var aggregateCatalog = new AggregateCatalog(assemblyCatalog, directoryCatalog);
var container = new CompositionContainer(aggregateCatalog);
container.SatisfyImportsOnce(this);
}
public static PluginsCatalog Instance { get { return LazyInstance.Value; } }
public IConnector GetConnector(string name)
{
var match = Connectors.SingleOrDefault(s => s.Metadata.Name.Equals(name));
return match == null ? null : match.Value;
}
}
}
The "Primary" IConnector
using System;
using System.Xml.Linq;
using Common;
namespace Common
{
[ConnectorMetadata("Primary")]
public class Connector : IConnector
{
public XDocument Run(object serviceCredentials, object connectorIds, object connectorKeys)
{
PluginsCatalog.Instance.GetConnector("Sub").Identify();
return default(XDocument);
}
public void Identify()
{
Console.WriteLine(GetType().FullName);
}
}
}
The "Sub" IConnector
using System;
using System.Xml.Linq;
using Common;
namespace SubPlugin
{
[ConnectorMetadata("Sub")]
public class SubConnector:IConnector
{
public XDocument Run(object serviceCredentials, object connectorIds, object connectorKeys)
{
return default(XDocument);
}
public void Identify()
{
Console.WriteLine(GetType().FullName);
}
}
}
and finally the program itself:
namespace SOMEF
{
class Program
{
static void Main(string[] args)
{
var connector = PluginsCatalog.Instance.GetConnector("Primary");
connector.Identify();
connector.Run(null, null, null);
}
}
}
Which prints:
SOMEF.Connector
SubPlugin.SubConnector
Hope this helps ... :)
You might want to read this https://msdn.microsoft.com/en-us/library/ee155691(v=vs.110).aspx
With exmplanation how named exports are used
public class MyClass
{
[Import("MajorRevision")]
public int MajorRevision { get; set; }
}
public class MyExportClass
{
[Export("MajorRevision")] //This one will match.
public int MajorRevision = 4;
[Export("MinorRevision")]
public int MinorRevision = 16;
}
i'm trying to generate Code at runtime which uses a custom class from another Namespace.
Here´s my code:
namespace Test.Programm.Network
{
class Handler
{
public void CreateAssembly()
{
string[] code =
{
#"using System;
using System.Collections;
namespace Test.Programm.Network
{
class HandleMessage
{
protected static internal Queue _queue;
public static void Received(string message)
{
lock (_queue)
{
_queue.Enqueue(message);
}
}
public HandleMessage()
{
_queue = new Queue();
}
}
}"
};
CompilerParameters parms = new CompilerParameters();
parms.GenerateExecutable = false;
parms.GenerateInMemory = true;
CodeDomProvider compiler = null;
compiler = CodeDomProvider.CreateProvider("CSharp");
CompilerResults compilerResults = compiler.CompileAssemblyFromSource(parms, code);
var cls = compilerResults.CompiledAssembly.GetType("Test.Programm.Network.HandleMessage");
Assembly assembly = compilerResults.CompiledAssembly;
var newHandler = assembly.CreateInstance(compilerResults.CompiledAssembly.GetType("Test.Programm.Network.HandleMessage").ToString());
}
}
}
But i don´t want to pass a string to my function, i want to pass an own type to that function.
Now i have a simple message class like that:
namespace Test.Programm.Messages
{
public class Message<T>
{
string _message;
}
}
if i want too add a using Test.Programm.Messages to the code i want to generate, i´m getting error that this Namespace doesn´t exist, missing reference...
I tried to add parms.ReferencedAssemblies.Add("Grid.Node.Messages"); to the code Generation, but this doesnt work. searching the web and SO haven´t given an answer yet -.-
Thanks for your help.
You should reference the assembly instead of the namespace. Something like this:
parms.ReferencedAssemblies.Add("path_to.dll");
Where path_to.dll is a path to the assembly file containing type Message<T>.
I am trying to make an instance of a class based on a string that will be retrieved from the User Interface, and then I want to access the properties of the instance of the class.
Here is an overview of what I have so far -
namespace MamdaAdapter
{
public interface IExchange
{
string GetTransport();
}
}
namespace MamdaAdapter
{
public class Exchange
{
public class Arca : IExchange
{
private const string _Transport = "tportname";
public string GetTransport()
{
return _Transport;
}
}
public static IExchange DeriveExchange(string ExchangeName)
{
IExchange SelectedExchange = (IExchange)Activator.CreateInstance(Type.GetType(ExchangeName));
return SelectedExchange;
}
}
}
namespace MyUserInterface
{
public class MainForm
{
private void simpleButton1_Click(object sender, EventArgs e)
{
IExchange SelectedExchange = Exchange.DeriveExchange("Exchange.Arca");
Console.WriteLine(SelectedExchange.GetTransport());
}
}
}
UPDATE:
Right now, I'm getting an Exception that says the "Value cannot be null" which to me means that it is unable to create the instance of the class given the string provided -
The problem here is how you specify the name of your class:
First, specify the namespace. Second, since Arca is an inner class you must use '+' instead of '.'
(...) = Exchange.DeriveExchange("MamdaAdapter.Exchange+Arca");
Assuming you UI doesnt expose the full type name, you typically want a dictionary to associate the display name to the type:
Dictionary<string, Type> _associations = new Dictionary<string, Type>();
Then, you simply instantiate the new object:
if(_associations.ContainsKey(someString))
{
Type selectedType = _associations[someString];
return Activator.CreateInstance(selectedType) as IExchange;
}
throw new ApplicationException("No type defined for that string yo");
If the string is not known at compile time, you basically need to check for the existance of the type:
var type = Type.GetType(someString);
if(type != null)
{
// Do Stuff
}
I wrote a small c# console application to simulate your need, tested ok, hope it helps:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MamdaAdapter;
using System.Reflection;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
IExchange SelectedExchange = Exchange.DeriveExchange("MamdaAdapter.Arca");
Console.WriteLine(SelectedExchange.GetTransport());
}
}
}
namespace MamdaAdapter
{
public interface IExchange
{
string GetTransport();
}
}
namespace MamdaAdapter
{
public class Arca : IExchange
{
private const string _Transport = "tportname";
public string GetTransport()
{
return _Transport;
}
}
}
namespace MamdaAdapter
{
public class Exchange
{
public static IExchange DeriveExchange(string ExchangeName)
{
IExchange SelectedExchange = (IExchange)Assembly.GetAssembly(typeof(IExchange)).CreateInstance(ExchangeName, false, BindingFlags.CreateInstance, null, null, null, null);
return SelectedExchange;
}
}
}
If the Type you are looking for is not defined in the same assembly that is executing Type.GetType you must use the AssemblyQualifiedName (something like MyNamespace.MyClass, MyAssembly, Version=1.3.0.0, Culture=neutral, PublicKeyToken=b17a5c561934e089), even the FullName is not enough. Otherwise you could first get the assembly containing the class and then execute the GetType method of the Assembly class.
I'm currently using MEF in my project, however, a legacy component uses Castle to export all its components.
I would like to be able to Import from this kernel when creating new objects, in addition to getting the exports from the Xap.
Is this possible? Can you show me some example code?
MEF was designed to be as flexible as possible, and one of its secretly hidden but real nice features, is the ability to define new ExportProvider instances, that allow you to plug in additional components. I've talked about this previously by utilising the Common Service Locator project in an ASP.NET MVC with MEF Project (see part 3 here).
The CSL is a nice flexible approach, as there are many specific CSL implementations for many of the existing IoC containers, such as Castle, Autofac, Ninject, Unity etc.
Another good example can be found here, which demonstrates a slightly different, but fundamentally similar approach.
As Matthew correctly said, the way to do this is using an ExportProvider
Another example is here (it demonstrates exports from Xaml).
Below is what I did in the end to solve the problem.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.Primitives;
using System.Linq;
using Castle.MicroKernel;
using Castle.MicroKernel.Registration;
using Castle.Windsor;
namespace MEFCastleBridge
{
public class CastleExportProvider : ExportProvider
{
WindsorContainer _container;
private readonly Dictionary<ExportDefinition, List<Export>> _exports =
new Dictionary<ExportDefinition, List<Export>>();
private readonly object _sync = new object();
public CastleExportProvider(WindsorContainer container)
{
_container = container;
var handlers = _container.Kernel.GetAssignableHandlers(typeof(object));
foreach (var handler in handlers)
{
RegisterCastleComponent(handler);
}
_container.Kernel.ComponentRegistered += ComponentRegistered;
}
protected override IEnumerable<Export> GetExportsCore(
ImportDefinition definition, AtomicComposition atomicComposition)
{
var contractDefinition = definition as ContractBasedImportDefinition;
var retVal = Enumerable.Empty<Export>();
if (contractDefinition != null)
{
string contractName = contractDefinition.ContractName;
if (!string.IsNullOrEmpty(contractName))
{
var exports =
from e in _exports
where string.Compare(e.Key.ContractName, contractName, StringComparison.OrdinalIgnoreCase) == 0
select e.Value;
if (exports.Count() > 0)
{
retVal = exports.First();
}
}
}
return retVal;
}
void RegisterCastleComponent(IHandler handler)
{
var type = handler.Service;
var contractName = type.ToString();
lock (_sync)
{
var found = from e in _exports
where string.Compare(e.Key.ContractName,
contractName, StringComparison.OrdinalIgnoreCase) == 0
select e;
if (found.Count() == 0)
{
var metadata = new Dictionary<string, object>();
var definition = new ExportDefinition(contractName, metadata);
_exports.Add(definition, new List<Export>());
}
var wrapper = new Export(contractName, () => _container.Resolve(type));
found.First().Value.Add(wrapper);
}
}
void ComponentRegistered(string key, IHandler handler)
{
RegisterCastleComponent(handler);
}
}
public interface IMyComponent
{
string TheString { get; }
}
public class RegisteredComponent : IMyComponent
{
public string TheString { get { return "RegisteredComponent"; } }
}
[Export(typeof(IMyComponent))]
public class ExportedComponent : IMyComponent
{
public string TheString { get { return "ExportedComponent"; } }
}
public class ExportExample
{
// Will contain an instance of RegisteredComponent and ExportedComponent
[ImportMany]
public List<IMyComponent> Components { get; set; }
public ExportExample()
{
// Create a Windsor container and add a type.
var container = new WindsorContainer();
container.Register(Component.For<IMyComponent>().ImplementedBy<MyComponent>().LifeStyle.Singleton);
// Add the Export Provider, in addition to the DeploymentCatalog
var compContainer = new CompositionContainer(new DeploymentCatalog(), new CastleExportProvider(container));
// Should only be called once, before any attempt to SatisfyImports.
CompositionHost.Initialize(compContainer);
CompositionInitializer.SatisfyImports(this);
Test = string.Join(", ", Components.Select(c => c.DoSomething));
}
public string Test { get; set; }
}
}