I created a WCF consuming application in WPF by adding service reference.Now its working fine.But now i have a new requirement that is, i want to call the service dynamically by entering the URL,username and password.
You can create a WCF client without adding a service reference with the use of ClientBase, but you will still need a reference to the interface for the compiler to knowwhat functions to call.
It works like this:
public class ServiceClient : System.ServiceModel.ClientBase<IService>, IService {
public ServiceClient() {
}
public ServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :
base(binding, remoteAddress) {
}
public void Login(string user, string password) {
return base.Channel.Login(user, password);
}
}
NetNamedPipeBinding binding = new NetNamedPipeBinding();
binding.TransactionFlow = true;
EndpointAddress address = new EndpointAddress(youraddress);
ServiceClient client = new ServiceClient(binding, address);
client.Login("xxx", "yyy");
See this website for a general idea. Create a new VisualStudio Solution and add a WCF Service Application project and an Unit Test Project. Put the following code in the test project (a slightly modified version of the code in the link) and add the missing references to the unit test project. Start the WCF service without debugging, change the portnumber in the test if needed and run the test. As mentioned in the article, the code can still use some adjustments before it could be put into production.
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.Xml.Linq;
namespace UnitTestProject1
{
public class ServiceDetail
{
public Uri WSDLUri { get; set; }
public Uri ServiceUri { get; set; }
public String ContractName { get; set; }
public string MethodName { get; set; }
}
public class GenericService
{
public object Call(ServiceDetail svc, List<object> payLoads)
{
//Import WSDL
WsdlImporter imptr = ImportWSDL(svc.WSDLUri);
//Extract Service and Data Contract Descriptions
Collection<ContractDescription> svcCtrDesc = imptr.ImportAllContracts();
//Compile the description to assembly
var assembly = GetAssembly(svcCtrDesc);
if (assembly == null) return null;
//Extract all end points available on the WSDL
IDictionary<string, IEnumerable<ServiceEndpoint>> allEP = GetEndPointsOfEachServiceContract(imptr, svcCtrDesc);
IEnumerable<ServiceEndpoint> currentSvcEP;
if (allEP.TryGetValue(svc.ContractName, out currentSvcEP))
{
//Find the endpoint of the service to which the proxy needs to contact
var svcEP = currentSvcEP.First(x => x.ListenUri.AbsoluteUri == svc.ServiceUri.AbsoluteUri);
//Generate proxy
var proxy = GetProxy(svc.ContractName, svcEP, assembly);
//Deserialize each payload argument to object
List<object> pls = new List<object>();
foreach (var pl in payLoads)
{
object clrObj = null;
try
{
clrObj = Deserialize(pl.ToString(), assembly);
}
catch
{
clrObj = pl;
}
pls.Add(clrObj);
}
//Find opration contract on the proxy and invoke
return proxy.GetType().GetMethod(svc.MethodName).Invoke(proxy, pls.ToArray());
}
return null;
}
private Assembly GetAssembly(Collection<ContractDescription> svcCtrDesc)
{
CodeCompileUnit ccu = GetServiceAndDataContractCompileUnitFromWSDL(svcCtrDesc);
CompilerResults rslt = GenerateContractsAssemblyInMemory(new CodeCompileUnit[] { ccu });
if (!rslt.Errors.HasErrors)
return rslt.CompiledAssembly;
return null;
}
private object GetProxy(string ctrName, ServiceEndpoint svcEP, Assembly assembly)
{
Type prxyT = assembly.GetTypes().First(t => t.IsClass && t.GetInterface(ctrName) != null && t.GetInterface(typeof(ICommunicationObject).Name) != null);
object proxy = assembly.CreateInstance(prxyT.Name, false, System.Reflection.BindingFlags.CreateInstance,
null, new object[] { svcEP.Binding, svcEP.Address }, CultureInfo.CurrentCulture, null);
return proxy;
}
private WsdlImporter ImportWSDL(Uri wsdlLoc)
{
MetadataExchangeClient mexC = new MetadataExchangeClient(wsdlLoc, MetadataExchangeClientMode.HttpGet);
mexC.ResolveMetadataReferences = true;
MetadataSet metaSet = mexC.GetMetadata();
return new WsdlImporter(metaSet);
}
private Dictionary<string, IEnumerable<ServiceEndpoint>> GetEndPointsOfEachServiceContract(WsdlImporter imptr, Collection<ContractDescription> svcCtrDescs)
{
ServiceEndpointCollection allEP = imptr.ImportAllEndpoints();
var ctrEP = new Dictionary<string, IEnumerable<ServiceEndpoint>>();
foreach (ContractDescription svcCtrDesc in svcCtrDescs)
{
List<ServiceEndpoint> eps = allEP.Where(x => x.Contract.Name == svcCtrDesc.Name).ToList();
ctrEP.Add(svcCtrDesc.Name, eps);
}
return ctrEP;
}
private CodeCompileUnit GetServiceAndDataContractCompileUnitFromWSDL(Collection<ContractDescription> svcCtrDescs)
{
ServiceContractGenerator svcCtrGen = new ServiceContractGenerator();
foreach (ContractDescription ctrDesc in svcCtrDescs)
{
svcCtrGen.GenerateServiceContractType(ctrDesc);
}
return svcCtrGen.TargetCompileUnit;
}
private object Deserialize(string xml, Assembly assembly)
{
Type ctr = GetDataContractType(xml, assembly);
return Deserialize(xml, ctr);
}
private object Deserialize(string xml, Type toType)
{
using (Stream stream = new MemoryStream())
{
byte[] data = System.Text.Encoding.UTF8.GetBytes(xml);
stream.Write(data, 0, data.Length);
stream.Position = 0;
DataContractSerializer d = new DataContractSerializer(toType);
return d.ReadObject(stream);
}
}
private Type GetDataContractType(string xml, Assembly assembly)
{
var serializedXML = ConvertToXML(xml);
var match = assembly.GetTypes().First(x => x.Name == serializedXML.Root.Name.LocalName);
return match;
}
private XDocument ConvertToXML(string xml)
{
using (Stream stream = new MemoryStream())
{
byte[] data = System.Text.Encoding.UTF8.GetBytes(xml);
stream.Write(data, 0, data.Length);
stream.Position = 0;
return XDocument.Load(stream);
}
}
private CompilerResults GenerateContractsAssemblyInMemory(params CodeCompileUnit[] codeCompileUnits)
{
// Generate a code file for the contracts
CodeGeneratorOptions opts = new CodeGeneratorOptions();
opts.BracingStyle = "C";
CodeDomProvider pro = CodeDomProvider.CreateProvider("C#");
// Compile the code file to an in-memory assembly
// Don't forget to add all WCF-related assemblies as references
CompilerParameters prms = new CompilerParameters(new string[] { "System.dll", "System.ServiceModel.dll",
"System.Runtime.Serialization.dll"});
prms.GenerateInMemory = true;
prms.GenerateExecutable = false;
return pro.CompileAssemblyFromDom(prms, codeCompileUnits);
}
}
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
// Arrange
var target = new GenericService();
var serviceDetail = new ServiceDetail
{
WSDLUri = new Uri("http://localhost:13152/Service1.svc?singleWsdl"),
ServiceUri = new Uri("http://localhost:13152/Service1.svc"),
ContractName = "IService1",
MethodName = "GetData"
};
var arguments = new List<object> { 5 };
// Act
var result = target.Call(serviceDetail, arguments);
// Assert
Assert.AreEqual("You entered: 5", result);
}
}
}
Related
I serialized a class to XML. But deserialization to the same class type is failing when schema validation is enabled.
Here is what I'm doing:
creating an object from the serializable class
Serializing that object to XML
Gets the schema from the that object
Adds that schema to validation
deserialize with out validation
deserialize with XMLschema validation
In step six, it is failing...
Here in this code sample, method with validation is failing:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
namespace Deserialize
{
public class Program
{
static string filepath = "TestSerilize.xml";
private static object oSchema;
private static XmlReaderSettings oXmlReaderSettings;
static void Main(string[] args)
{
MyObject oMyobject = new MyObject();
oMyobject.MyObjectType = "MyCustomType";
List<Items> olistItems = new List<Items>();
Items oItems = new Items();
oItems.key = "test123";
oItems.value = "testvalue";
olistItems.Add(oItems);
oMyobject.Items = olistItems;
Saveobjecttofile(oMyobject, filepath);
dynamic objDeserialized = null;
objDeserialized = GetObjFormfileWithoutValidation(filepath, oMyobject.GetType());
objDeserialized = GetObjFormfileWithValidation(filepath, oMyobject.GetType());
}
private static dynamic GetObjFormfileWithValidation(string filepath, Type type)
{
XmlReaderSettings oXmlReaderSettings = new XmlReaderSettings();
oXmlReaderSettings.ValidationType = ValidationType.Schema;
dynamic oSchema = GetSchemaFromType(type);
oXmlReaderSettings.Schemas.Add(oSchema);
XmlReader oXmlReader = null;
if (oSchema != null)
{
oXmlReader = XmlReader.Create(filepath, oXmlReaderSettings);
}
else
{
oXmlReader = XmlReader.Create(filepath);
}
object obj = null;
try
{
XmlSerializer oXmlSerializer = new XmlSerializer(type);
obj = oXmlSerializer.Deserialize(oXmlReader);
}
finally
{
oXmlReader.Close();
}
return obj;
}
private static XmlSchema GetSchemaFromType(Type type)
{
var oSoapReflectionImporter = new SoapReflectionImporter();
var oXmlTypeMapping = oSoapReflectionImporter.ImportTypeMapping(type);
var oXmlSchemas = new XmlSchemas();
var oXmlSchema = new XmlSchema();
oXmlSchemas.Add(oXmlSchema);
var oXMLSchemaExporter = new XmlSchemaExporter(oXmlSchemas);
oXMLSchemaExporter.ExportTypeMapping(oXmlTypeMapping);
return oXmlSchema;
}
private static dynamic GetObjFormfileWithoutValidation(string filepath, Type type)
{
XmlReader oXmlReader = null;
oXmlReader = XmlReader.Create(filepath);
object obj = null;
try
{
XmlSerializer oXmlSerializer = new XmlSerializer(type);
obj = oXmlSerializer.Deserialize(oXmlReader);
}
finally
{
oXmlReader.Close();
}
return obj;
}
private static void Saveobjecttofile(object objectToSave, string filepath)
{
try
{
System.Xml.Serialization.XmlSerializer oXmlSerializer = new System.Xml.Serialization.XmlSerializer(objectToSave.GetType());
using (System.Xml.XmlTextWriter oXmlTextWriter = new System.Xml.XmlTextWriter(filepath, System.Text.Encoding.UTF8))
{
oXmlTextWriter.Indentation = 2;
oXmlTextWriter.Formatting = System.Xml.Formatting.Indented;
oXmlSerializer.Serialize(oXmlTextWriter, objectToSave);
oXmlTextWriter.Flush();
oXmlTextWriter.Close();
}
}
catch (Exception)
{ throw; }
}
}
[XmlType("Items")]
public class Items
{
[XmlAttribute("key")]
public string key { get; set; }
[XmlText()]
public string value { get; set; }
}
[Serializable, XmlRoot("MyObject")]
public class MyObject
{
[XmlElement("MyObjectType", IsNullable = true)]
public string MyObjectType { get; set; }
[XmlElement("Items")]
public List<Items> Items;
public string this[string key]
{
get
{
return null != Items.Find(x => x.key == key) ? Items.Find(x => x.key == key).value : null;
}
set
{
if (Items == null) Items = new List<Items>();
if (null != Items.Find(x => x.key == key))
{
Items.Find(x => x.key == key).value = value;
}
else
{
Items.Add(new Items { key = key, value = value });
}
}
}
}
}
Exception details:
System.Xml.Schema.XmlSchemaException
Message:There is an error in XML document (3, 10).
Inner Exception message:The 'key' attribute is not declared.
StackTrace:
at system.Xml.Schema.XmlSchemaValidator.SendValidationEvent(XmlSchemaValidationException e, XmlSeverityType severity)
at System.Xml.Schema.XmlSchemaValidator.SendValidationEvent(String code, String arg)
at System.Xml.Schema.XmlSchemaValidator.ValidateAttribute(String lName, String ns, XmlValueGetter attributeValueGetter, String attributeStringValue, XmlSchemaInfo schemaInfo)
at System.Xml.Schema.XmlSchemaValidator.ValidateAttribute(String localName, String namespaceUri, XmlValueGetter attributeValue, XmlSchemaInfo schemaInfo)
at System.Xml.XsdValidatingReader.ValidateAttributes()
at System.Xml.XsdValidatingReader.ProcessElementEvent()
at System.Xml.XsdValidatingReader.ProcessReaderEvent()
at System.Xml.XsdValidatingReader.Read()
at System.Xml.XmlReader.MoveToContent()
at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderMyObject.Read3_MyObject(Boolean isNullable, Boolean checkType)
at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderMyObject.Read4_MyObject()
Demo fiddle here.
Your problem is here:
private static XmlSchema GetSchemaFromType(Type type)
{
var oSoapReflectionImporter = new SoapReflectionImporter();
SoapReflectionImporter is designed to generate a schema for a c# type that has been marked with SOAP attributes. Such a schema can be used to generate an XmlSerializer customized to use such attributes, as shown in How to: Serialize an Object as a SOAP-Encoded XML Stream:
XmlTypeMapping myTypeMapping = new SoapReflectionImporter().ImportTypeMapping(type);
XmlSerializer mySerializer = new XmlSerializer(myTypeMapping);
You, however, are not using SOAP attributes. You are using regular XmlSerializer attributes, as can be see e.g. in your Items class:
[XmlType("Items")]
public class Items
{
[XmlAttribute("key")]
public string key { get; set; }
[XmlText()]
public string value { get; set; }
}
Thus you should be using XmlReflectionImporter instead:
private static XmlSchema GetSchemaFromType(Type type)
{
var oReflectionImporter = new XmlReflectionImporter();
var oXmlTypeMapping = oReflectionImporter.ImportTypeMapping(type);
var oXmlSchemas = new XmlSchemas();
var oXmlSchema = new XmlSchema();
oXmlSchemas.Add(oXmlSchema);
var oXMLSchemaExporter = new XmlSchemaExporter(oXmlSchemas);
oXMLSchemaExporter.ExportTypeMapping(oXmlTypeMapping);
return oXmlSchema;
}
Related: How do I programmatically generate an xml schema from a type?
Fixed sample demo here.
I have compilation of a dynamic assembly. I pass in a type. Explicitly set the property on it to be true. However on the returned object (obj1) the property (Complete) is still false. How do I get the correct value?
SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(#"
using System;
using System.Windows.Forms;
using System.Diagnostics;
using DynamicFormDemo;
using DynamicFormDemo.Controllers;
namespace InMemoryCompiledAssembly
{
public class Control
{
public static Host ProcessCompleteScript(Host host)
{/*
if ((Ctrl.FieldValue.ToString() != string.Empty) && (Ctrl.FieldValue != null))
{
Ctrl.Complete = true;
}
else
{
Ctrl.Complete = false;
} */
// var t = host.Control;
host.Control.Complete = true;
MessageBox.Show(host.Control.Complete.ToString());
return host;
}
}
}");
string assemblyName = Path.GetRandomFileName();
MetadataReference[] references = new MetadataReference[]
{
MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location),
MetadataReference.CreateFromFile(typeof(Debug).Assembly.Location),
MetadataReference.CreateFromFile(typeof(MessageBox).Assembly.Location),
MetadataReference.CreateFromFile(typeof(Host).Assembly.Location),
};
CSharpCompilation compilation = CSharpCompilation.Create(
assemblyName,
syntaxTrees: new[] { syntaxTree },
references: references,
options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
Assembly assembly = null;
using (var ms = new MemoryStream())
{
EmitResult result = compilation.Emit(ms);
if (!result.Success)
{
IEnumerable<Diagnostic> failures = result.Diagnostics.Where(diagnostic =>
diagnostic.IsWarningAsError ||
diagnostic.Severity == DiagnosticSeverity.Error);
foreach (Diagnostic diagnostic in failures)
{
Console.Error.WriteLine("{0}: {1}", diagnostic.Id, diagnostic.GetMessage());
}
}
else
{
ms.Seek(0, SeekOrigin.Begin);
assembly = Assembly.Load(ms.ToArray());
}
}
Host h = new Host();
h.Control = AVPControls[x];
Type type = assembly.GetType("InMemoryCompiledAssembly.Control");
object obj = Activator.CreateInstance(type);
Object obj1 = type.InvokeMember("ProcessCompleteScript",
BindingFlags.Default | BindingFlags.InvokeMethod | BindingFlags.Static | BindingFlags.Public,
null,
obj,
new object[] { h });
public class Host
{
public IAVPBaseControl Control { get; set; }
}
Given that you did not provide much insight into the details of the AVPMVCxFormLayoutItem class or the AVPControls reference, I recreated the scenario using the following:
public sealed class AVPMVCxFormLayoutItem
{
public bool Complete { get; set; }
}
I am unable to reproduce your issue.
This leads me to believe your problem lies within the AVPMVCxFormLayoutItem class itself.
I have a failing testcase that depends on an external module.
I want to use Rhino Mock to generate a report on called functions.
I created a minimal example that illustrates my problem:
using NUnit.Framework;
using Rhino.Mocks;
using System;
namespace StackOverflow_namespace
{
public interface IUsefulService
{
object HiddenAmongManyCalls();
}
public class ThirdPartyBase
{
private int a = 42;
public ThirdPartyBase(IUsefulService service)
{
object liveFastDieYoung = service.HiddenAmongManyCalls();
liveFastDieYoung.Equals(a);
}
}
public class MyParty : ThirdPartyBase
{
public MyParty(IUsefulService service) : base(service)
{
}
}
[TestFixture]
class StackOverflow
{
[Test]
public void Hypothetical()
{
IUsefulService service = MockRepository.GenerateMock<IUsefulService>();
try
{
var party = new MyParty(service);
}
catch(Exception e)
{
string[] calls = MagicallyGetTheCallsThatWereMadeToTheMock();
foreach(var call in calls)
{
//with my visual studio testrunner for nunit 3 I can investigate stored console output
Console.WriteLine(call);
}
Assert.Fail("Excpexted no exception but was '" + e.GetType().Name + "': " + e.Message);
}
}
private string[] MagicallyGetTheCallsThatWereMadeToTheMock()
{
return new[]
{
"This is where I am lost, I do not know how to get the calls from the repository."
};
}
}
}
I tried to find something online without success.
Do Rhino Mocks record all calls and can I access that list?
Edit:
An attempt to verify Expectations did not work since I am looking for calls I did not expect.
I could build a list of calls using GetArgumentsForCallsMadeOn. I can reflect on the Interface. I started on a method for that but I currently fail to see how I can convert a MethodInfo to an Action<T>.
private IEnumerable<string> GetCallsList<Interface>(Interface rhinomock)
{
Type interfaceType = typeof(Interface);
List<MethodInfo> interfaceMethodInfos = new List<MethodInfo>();
List<string> returnInfos = new List<string>();
StringBuilder callbuilder = new StringBuilder();
foreach (var property in interfaceType.GetProperties())
{
interfaceMethodInfos.Add(property.GetGetMethod());
interfaceMethodInfos.Add(property.GetSetMethod());
}
foreach (var method in interfaceType.GetMethods())
{
interfaceMethodInfos.Add(method);
}
foreach (var methodinfo in interfaceMethodInfos)
{
Action<Interface> magic = null; //convert methodinfo into action - still missing
var calls = rhinomock.GetArgumentsForCallsMadeOn(magic); //magic is currently null, here be crash
foreach (var call in calls)
{
bool more = false;
callbuilder.Clear().Append(interfaceType.Name).Append('.').Append(methodinfo.Name).Append('(');
foreach (var parameter in call)
{
if (more){ callbuilder.Append(", "); }
if (null == parameter) { callbuilder.Append("<null>"); }
else { callbuilder.Append(parameter.ToString()); }
more = true;
}
callbuilder.Append(')');
string callInfo = callbuilder.ToString();
returnInfos.Add(callInfo);
}
}
return returnInfos;
}
I was able to use reflection to get the output I wanted.
Here is the minimal example where the test fails and the output contains all method calls.
using NUnit.Framework;
using Rhino.Mocks;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
namespace StackOverflow_namespace
{
public interface IUsefulService
{
object HiddenAmongManyCalls();
string TestCall2(string arg1, int arg2);
string FULLACCESS { get; set; }
string READONLY { get; }
}
public class ThirdPartyBase
{
private int a = 42;
public ThirdPartyBase(IUsefulService service)
{
service.TestCall2("callA", 1);
service.TestCall2("callB", 1);
object liveFastDieYoung = service.HiddenAmongManyCalls();
service.TestCall2("callA", 2);
service.TestCall2("callB", 2);
var a = service.FULLACCESS;
var b = service.READONLY;
service.FULLACCESS = "some";
liveFastDieYoung.Equals(a);
}
}
public class MyParty : ThirdPartyBase
{
public MyParty(IUsefulService service) : base(service)
{
}
}
[TestFixture]
class StackOverflow
{
[Test]
public void Hypothetical()
{
IUsefulService service = MockRepository.GenerateMock<IUsefulService>();
try
{
var party = new MyParty(service);
}
catch (Exception e)
{
var calls = GetCallsList(service);
foreach (var call in calls)
{
//with my visual studio testrunner for nunit 3 I can investigate stored console output
Console.WriteLine(call);
}
Assert.Fail("Excpexted no exception but was '" + e.GetType().Name + "': " + e.Message);
}
}
private IEnumerable<string> GetCallsList<Interface>(Interface rhinomock)
{
Type interfaceType = typeof(Interface);
List<MethodInfo> interfaceMethodInfos = new List<MethodInfo>();
List<string> returnInfos = new List<string>();
StringBuilder callbuilder = new StringBuilder();
foreach (var property in interfaceType.GetProperties())
{
AddMethodInfoIfValid(interfaceMethodInfos, property.GetGetMethod());
AddMethodInfoIfValid(interfaceMethodInfos, property.GetSetMethod());
}
foreach (var method in interfaceType.GetMethods())
{
AddMethodInfoIfValid(interfaceMethodInfos, method);
}
foreach (var methodinfo in interfaceMethodInfos)
{
int paramcount = methodinfo.GetParameters().Length;
object[] args = new object[paramcount];
Action<Interface> lambdacall = (i) => methodinfo.Invoke(i, args);
var calls = rhinomock.GetArgumentsForCallsMadeOn(lambdacall);
foreach (var call in calls)
{
bool more = false;
callbuilder.Clear().Append(interfaceType.Name).Append('.').Append(methodinfo.Name).Append('(');
foreach (var parameter in call)
{
if (more) { callbuilder.Append(", "); }
if (null == parameter) { callbuilder.Append("<null>"); }
else {
callbuilder
.Append('(').Append(parameter.GetType().Name).Append(")'")
.Append(parameter.ToString()).Append("'");
}
more = true;
}
callbuilder.Append(')');
string callInfo = callbuilder.ToString();
returnInfos.Add(callInfo);
}
}
return returnInfos;
}
private static void AddMethodInfoIfValid(List<MethodInfo> interfaceMethodInfos, MethodInfo methodinfo)
{
if (null != methodinfo)
{
interfaceMethodInfos.Add(methodinfo);
}
}
}
}
i try to use CompileAssemblyFromSource to change 1 value at my main class.
But when i compile i get error "Could not load file or assembly or one of its dependencies" and this only happens when i try change static value of other class. But if i return some output or wrote anything at Console from this FooClass than all work's fine. But how can i change value of other class?
using System;
using System.CodeDom.Compiler;
using System.Reflection;
using Microsoft.CSharp;
namespace stringToCode
{
class Program
{
public static int q = 0;
static void Main(string[] args)
{
string source = "namespace stringToCode { public class FooClass { public void Execute() { Program.q = 1; } } }";
Console.WriteLine("q=" + q);
using (var foo = new CSharpCodeProvider())
{
var parameters = new CompilerParameters();
parameters.GenerateInMemory = true;
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
try
{
string location = assembly.Location;
if (!String.IsNullOrEmpty(location))
{
parameters.ReferencedAssemblies.Add(location);
}
}
catch (NotSupportedException)
{}
}
var res = foo.CompileAssemblyFromSource(parameters ,source);
var type = res.CompiledAssembly.GetType("FooClass"); //<- here i has error
var obj = Activator.CreateInstance(type);
var output = type.GetMethod("Execute").Invoke(obj, new object[] { });
Console.WriteLine("q=" + q);
Console.ReadLine();
}
}
}
}
You can't find the type because you have compilation error in your code.You can't access the classes in your current code in this manner. You should at least reference the current assembly in your in-memory assembly.
UPDATE
You have two issues in your code. First, you have to make the class Program public. Then you should specify the full name of type in GetType method.
This code works fine:
using System;
using System.CodeDom.Compiler;
using System.Reflection;
using Microsoft.CSharp;
namespace stringToCode
{
public class Program
{
public static int q = 0;
static void Main(string[] args)
{
string source = "namespace stringToCode { public class FooClass { public void Execute() { Program.q = 1; } } }";
Console.WriteLine("q=" + q);
using (var foo = new CSharpCodeProvider())
{
var parameters = new CompilerParameters();
parameters.GenerateInMemory = true;
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
try
{
string location = assembly.Location;
if (!String.IsNullOrEmpty(location))
{
parameters.ReferencedAssemblies.Add(location);
}
}
catch (NotSupportedException)
{}
}
var res = foo.CompileAssemblyFromSource(parameters ,source);
var type = res.CompiledAssembly.GetType("stringToCode.FooClass"); //<- here i has error
var obj = Activator.CreateInstance(type);
var output = type.GetMethod("Execute").Invoke(obj, new object[] { });
Console.WriteLine("q=" + q);
Console.ReadLine();
}
}
}
}
I compile a plugin and then create an instance of it in a new AppDomain. Then I want to execute a method in the plugin object but that results in an ArgumentException:
"Object of type System.MarshalByRefObject can not be converted to type Data"
The code below should be compilable and result in the exception above. To make it work you must also sign the Assembly (Project -> Properties -> Signing -> Sign the assembly -> New ...)
IPlugin.cs:
using System;
namespace Plugin
{
[Serializable]
class Data : MarshalByRefObject
{
int value;
}
interface IPlugin
{
void DoStuff(Data data);
}
}
Program.cs:
using System;
using System.CodeDom.Compiler;
using System.IO;
using System.Security.Policy;
using System.Security;
using System.Security.Permissions;
using System.Reflection;
namespace Plugin
{
class Program
{
public class Sandbox : MarshalByRefObject
{
const string BaseDirectory = "Untrusted";
const string DomainName = "Sandbox";
private object instance;
public static Sandbox Create()
{
var setup = new AppDomainSetup()
{
ApplicationBase = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, BaseDirectory),
ApplicationName = DomainName,
DisallowBindingRedirects = true,
DisallowCodeDownload = true,
DisallowPublisherPolicy = true
};
Evidence ev = new Evidence();
ev.AddHostEvidence(new Zone(SecurityZone.Internet));
var permissions = new PermissionSet(PermissionState.None);
permissions.AddPermission(new ReflectionPermission(ReflectionPermissionFlag.RestrictedMemberAccess));
permissions.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
StrongName fullTrustAssembly = typeof(Sandbox).Assembly.Evidence.GetHostEvidence<StrongName>();
var domain = AppDomain.CreateDomain(DomainName, null, setup, permissions, fullTrustAssembly);
return (Sandbox)Activator.CreateInstanceFrom(domain, typeof(Sandbox).Assembly.ManifestModule.FullyQualifiedName, typeof(Sandbox).FullName).Unwrap();
}
public bool CreateInstance(string assemblyPath, string scriptType)
{
new FileIOPermission(FileIOPermissionAccess.Read | FileIOPermissionAccess.PathDiscovery, assemblyPath).Assert();
var assembly = Assembly.LoadFrom(assemblyPath);
CodeAccessPermission.RevertAssert();
Type type = assembly.GetType(scriptType);
if (type == null)
return false;
instance = Activator.CreateInstance(type);
return instance != null;
}
public object Execute(string method, params object[] parameters)
{
Type type = instance.GetType();
MethodInfo info = type.GetMethod(method);
return info.Invoke(instance, parameters);
}
}
private static void CompileToFile(string code, string ifaceFile, string output)
{
CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
CompilerParameters p = new CompilerParameters();
p.GenerateInMemory = false;
p.GenerateExecutable = false;
p.OutputAssembly = output;
provider.CompileAssemblyFromSource(p, code, ifaceFile);
}
private static string code = #"
using Plugin;
class MyPlugin : IPlugin
{
public void DoStuff(Data data)
{
}
}
";
static void Main(string[] args)
{
string iface = System.IO.File.ReadAllText(#"C:\Documents and Settings\markus.BLUE\mina dokument\visual studio 2010\Projects\Plugin\Plugin\IPlugin.cs");
string pluginObjectFile = System.IO.Path.GetTempFileName();
CompileToFile(code, iface, pluginObjectFile);
Sandbox s = Sandbox.Create();
s.CreateInstance(pluginObjectFile, "MyPlugin");
Data data = new Data();
s.Execute("DoStuff", data);
}
}
}
It must be a type known at both sides of your communication!