My Req. is I want to call WCF Service Dynamically, just WSDL and interface name and method name will be provided, arguments given in dictionary/any collection. I want to call an operation contract dynamically which has parametrs as simple type and complex types.
My Service:-
public class CalculatorService : ICalculator
{
public double Add(double n1, double n2)
{
return n1 + n2;
}
public EmployeeOutput ProcessEmployee(EmployeeInput obj,string str, int i)
{
EmployeeOutput objOut = new EmployeeOutput();
objOut.EmpNo = obj.EmpNo;
objOut.EmpName = obj.EmpName;
return objOut;
}
[DataContract]
public class EmployeeInput
{
[DataMember]
public string EmpNo { get; set; }
[DataMember]
public string EmpName { get; set; }
}
From client, I am trying to do this, since I had complex Type(EmployeeInput and primitive type string, int) and in complex type I had properties and fields, issue I am facing is mapping the inputs to service parameters for complex types as well as primitive types. My Code at client:
static class ObjectExtensions
{
public static void SetPropertyValue<T>(this object obj, string propertyName, T propertyValue)
where T : IConvertible
{
PropertyInfo pi = obj.GetType().GetProperty(propertyName);
if (pi != null && pi.CanWrite)
{
pi.SetValue
(
obj,
Convert.ChangeType(propertyValue, pi.PropertyType),
null
);
}
}
}
class Program
{
static void Main(string[] args)
{
CompilerResults compilerResults = null;
object proxyInstance = GetProxyInstance(ref compilerResults);
string operationName = "ProcessEmployee";
MethodInfo methodInfo = proxyInstance.GetType().GetMethod(operationName);
ParameterInfo[] paramInfos = methodInfo.GetParameters();
OrderedDictionary valueList = new OrderedDictionary();
IList<Object> parameter = new List<Object>();
//Object[] parameter = new Object[10];
for (int paramIndex = 0; paramIndex < paramInfos.Length; paramIndex++)
{
int i = 1;
var parameterType = paramInfos[paramIndex].ParameterType;
bool IsPrimitive = parameterType.GetType().IsPrimitive;
Object parameter2 = new Object();
if (parameterType.Namespace.StartsWith("System"))
{
parameter2.SetPropertyValue("str", "Test");
//parameterType.GetProperties()[i].SetValue(parameter2, "Test", null);
}
else
{
parameter2 = compilerResults.CompiledAssembly.CreateInstance(parameterType.FullName, false, BindingFlags.CreateInstance, null, null, null, null);
EmployeeInput obj = new EmployeeInput();
obj.EmpNo = "123";
obj.EmpName = "Test";
Console.WriteLine(parameter2.GetType());
Console.WriteLine(obj.GetType());
parameter2.SetPropertyValue("EmpNo", 123);
parameter2.SetPropertyValue("EmpName", "Test");
//parameterType.GetProperties()[i].SetValue(parameter2, Convert.ChangeType(obj, parameter2.GetType()), null);
//parameterType.GetProperties()[i].SetValue(parameter2, obj, null);
}
parameter.Add(parameter2);
//parameter[paramIndex] = parameter2;
i++;
}
object[] operationParameters = new object[] { parameter };
var result = methodInfo.Invoke(proxyInstance, BindingFlags.InvokeMethod, null, operationParameters, null);
The above code is failing when mapping complex fields. I mean from client, client send a collection, ex:- Dictionary collection with complex types, primitive types, I should be able to invoke my operationContract at service Side, this is my requirement.
WSDL Code Generation I'm already doing in CreateInstance,
public static object GetProxyInstance(ref CompilerResults compilerResults)
{
object proxyInstance = null;
// Define the WSDL Get address, contract name and parameters, with this we can extract WSDL details any time
//Uri address = new Uri("http://localhost:8732/CalculatorService/?wsdl");
//Uri address = new Uri("http://localhost/APG.WCFService/APGService.svc?wsdl");
Uri address = new Uri("http://localhost:8732/CalculatorService/?wsdl");
// For HttpGet endpoints use a Service WSDL address a mexMode of .HttpGet and for MEX endpoints use a MEX address and a mexMode of .MetadataExchange
MetadataExchangeClientMode mexMode = MetadataExchangeClientMode.HttpGet;
string contractName = "ICalculator";
//string contractName = "IAPGService";
// Get the metadata file from the service.
MetadataExchangeClient metadataExchangeClient = new MetadataExchangeClient(address, mexMode);
metadataExchangeClient.ResolveMetadataReferences = true;
//One can also provide credentials if service needs that by the help following two lines.
//ICredentials networkCredential = new NetworkCredential("", "", "");
//metadataExchangeClient.HttpCredentials = networkCredential;
//Gets the meta data information of the service.
MetadataSet metadataSet = metadataExchangeClient.GetMetadata();
// Import all contracts and endpoints.
WsdlImporter wsdlImporter = new WsdlImporter(metadataSet);
//Import all contracts.
Collection<ContractDescription> contracts = wsdlImporter.ImportAllContracts();
//Import all end points.
ServiceEndpointCollection allEndpoints = wsdlImporter.ImportAllEndpoints();
// Generate type information for each contract.
ServiceContractGenerator serviceContractGenerator = new ServiceContractGenerator();
//Dictinary has been defined to keep all the contract endpoints present, contract name is key of the dictionary item.
var endpointsForContracts = new Dictionary<string, IEnumerable<ServiceEndpoint>>();
foreach (ContractDescription contract in contracts)
{
serviceContractGenerator.GenerateServiceContractType(contract);
// Keep a list of each contract's endpoints.
endpointsForContracts[contract.Name] = allEndpoints.Where(ep => ep.Contract.Name == contract.Name).ToList();
}
// Generate a code file for the contracts.
CodeGeneratorOptions codeGeneratorOptions = new CodeGeneratorOptions();
codeGeneratorOptions.BracingStyle = "C";
// Create Compiler instance of a specified language.
CodeDomProvider codeDomProvider = CodeDomProvider.CreateProvider("C#");
// Adding WCF-related assemblies references as copiler parameters, so as to do the compilation of particular service contract.
CompilerParameters compilerParameters = new CompilerParameters(new string[] { "System.dll", "System.ServiceModel.dll", "System.Runtime.Serialization.dll" });
compilerParameters.GenerateInMemory = true;
//Gets the compiled assembly.
compilerResults = codeDomProvider.CompileAssemblyFromDom(compilerParameters, serviceContractGenerator.TargetCompileUnit);
if (compilerResults.Errors.Count <= 0)
{
// Find the proxy type that was generated for the specified contract (identified by a class that implements the contract and ICommunicationbject - this is contract
//implemented by all the communication oriented objects).
Type proxyType = compilerResults.CompiledAssembly.GetTypes().First(t => t.IsClass && t.GetInterface(contractName) != null &&
t.GetInterface(typeof(ICommunicationObject).Name) != null);
// Now we get the first service endpoint for the particular contract.
ServiceEndpoint serviceEndpoint = endpointsForContracts[contractName].First();
// Create an instance of the proxy by passing the endpoint binding and address as parameters.
proxyInstance = compilerResults.CompiledAssembly.CreateInstance(proxyType.Name, false, System.Reflection.BindingFlags.CreateInstance, null,
new object[] { serviceEndpoint.Binding, serviceEndpoint.Address }, CultureInfo.CurrentCulture, null);
}
return proxyInstance;
}
Thanks In Advance,
I suggest you make use of the Wsdl utility tool to generate the web service proxy dynamically. Then using the CodeDom to compile the code to a runtime assembly and call it dynamically from your code.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.