Invoking WCF functions using Reflection - c#

I have a WCF application that is using NetTcpBinding. I want to invoke the functions in WCF service using Methodbase.Invoke from the System.Reflection namespace. In other words I want to Dynamically call a Function by passing a String as the Function name.
Reflection works great for Web Service or a Windows application or any DLL or class. So there is certainly a way to do this for WCF but I am unable to find out how.
I am getting the Assembly Name then it's type everything fine but as we cannot create an instance of the Interface class. I tried to open the WCF connection using the binding and tried to pass that object but it's throwing an exception as:
"Object does not match target type."
I have opened the connection and passed the object and type is of interface only. I don't know whether I'm trying the wrong thing or am using the wrong way. Any idea how I can accomplish this?
The NetTCPBinding all are properly given while opening the connection. I am using WCF as a Windows Service using NETTCPBinding.

You are passing the correct instance when you invoke your method. This instance is the proxy object created via the interface-based call to ChannelFactory. I tried your technique on a hello world style application and got the expected results. One thing I don't see in your code example is how you initialize the parameters. That could be a problem. I believe think that your call to Type.GetType may be causing the error you are receiving. Notice I call GetType on the Proxy object. I include my sample code below that calls a Function GetData that takes one argument as an integer.
...
Dim myFactory As ChannelFactory(Of SimpleService.IService1)
myFactory = New ChannelFactory(Of SimpleService.IService1)(myBinding, myEndpoint)
oProxy = myFactory.CreateChannel()
'commented out version that does same call without reflection
' oProxy.GetData(3)
Dim oType As Type = oProxy.GetType
Dim oMeth As MethodInfo = oType.GetMethod("GetData")
Dim params() As Object = {3}
Dim sResults As String
sResults = oMeth.Invoke(oProxy, BindingFlags.Public Or BindingFlags.InvokeMethod, Nothing, params, System.Globalization.CultureInfo.CurrentCulture)

Related

c# SOAP with service reference is not showing real response

I'm creating an UWP app, that needs to connect to asmx service. I've done that by using service reference, which works with TempConvert but not with my asmx service
This is how my code looks like
HelpdeskSoapClient HPsoapClient = new HelpdeskSoapClient();
getIncInput input = new getIncInput();
input.username = "450";
getIncResponse realresponse;
realresponse= await HPsoapClient.getIncAsync(input);
Debug.Write(realresponse);
but response is not an XML file or something else, but "DTS.helpdesk.getIncResponse"
Any clues ?
getIncResponse is the object that is returned by the service when you make the call.
When you pass realResponse into the Debug.Write, since it's an object, the base functionality of ToString() is called, which unless overridden in the object will return the fully qualified type name - i.e., DTS.helpdesk.getIncResponse.
You should be able to access the properties of the object to get the data, similar to how you set the username on the getIncInput object (input.username = "450";).
The temperature conversion service worked because it returns a simple type (string), not a complex type (getIncResponse). There is no error here.

Utilizing IHeaderHandler with wcf

I have a rather outdated assembly that I'm using to communicate via SOAP with software my company writes. As it stands right now, getting the assembly updated is not an option, so please don't suggest it.
In previous iterations the normal method of communication was done utilizing the MS Soap Toolkit 3.0 (MSSOAPLIB30). You would call the login() method of the assembly and it would return an instance derived from IHeaderHandler that you would then assign to the instance of the soap client. Please refer here for more information on how this worked.
Well, I would like to use a more updated approach for communication with this web service. Thus far I have been able to successfully reference the web service with wcf, however I'm running into issues figuring out how to bridge the IHeaderHandler instance to something that the wcf proxy can comprehend. In other words, I'm trying to bridge two generations of technologies together. I've verified that using the method mentioned in the link above does actually work. Now it's just a matter of figuring out how to make this instance of IHeaderHandler useful.
Here is some example code for the old approach:
string strBasicWsdlUrl = "http://" + _strDeviceName + "/MetasysIII/WS/TimeManagement/TimeService.asmx";
object[] Parameters1 = new object[] { strBasicWsdlUrl, "", "", "" };
bool[] Parameters2 = new bool[] { true, true, true, true };
TSClient = Activator.CreateInstance(Type.GetTypeFromProgID("MSSOAP.SoapClient30"));
NewLateBinding.LateGet(TSClient, null, "MSSoapInit", Parameters1, null, null, Parameters2);
Parameters1 = new object[] { NewLateBinding.LateGet(JCISecurity, null, "HeaderHandler", new object[0], null, null, null) };
NewLateBinding.LateSet(TSClient, null, "HeaderHandler", Parameters1, null, null);
As you can see, a new instance of the soap client is initialized with the wsdl file and then the HeaderHandler attribute from the JCISecurity instance (which is the aforementioned assembly I'm using to authenticate with the software) which is derived from IHeaderHandler is passed to the HeaderHandler of the soap client. This process then ensures that all future requests from the soap client have this header attached.
It's also important to note that the proxy class generated from WCF for my web service has two interesting parameters attached to all web methods: EncryptedCertificate and LoginResult. I'm assuming these values will exist in the IHeaderHandler instance as the original documentation of the service does not reference these two parameters. However, I cannot verify this is the case because I've yet to be able to figure out how to access the content embedded in the IHeaderHandler instance.
As it stands, I see two possible solutions at this point: Figure out a way to make the WCF proxy class directly use the IHeaderHandler instance being generated with the assembly or figure out a way to extract the necessary information from the IHeaderHandler instance and use Message Inspectors to manually attach the details to the headers.
WCF is very extensible. One of those extension points is Message Inspectors:
A message inspector is an extensibility object that can be used in the service model's client runtime and dispatch runtime programmatically or through configuration and that can inspect and alter messages after they are received or before they are sent.
See also WCF Extensibility Samples and Extending WCF.

.NET WebService WebMethod with custom object as Parameter

I have created a .NET WebService. There I have implemented the following WebMethod:
[WebMethod]
public string CheckLicense(License license) {
return "";
}
The Type License comes from a different Assembly X which I have referenced to the WebService. The Fulltype of License is Prayon.Shared.Library.Licensing.License
Now, I have build a client which also references the Assembly X. When I try no to call the WebService with CheckLincense:
private void CheckLicense(License license) {
using(var service = new Prayon.Service.Web.PrayonService()) {
service.CheckLicense(license);
}
}
There service.CheckLicense() want an object of Type Prayon.Service.Prayon.Service.Web.License.
I don't know what I am doing wrong. What does I have to do, that I can pass a object of Type Prayon.Shared.Library.Licensing.License to service.CheckLicense()?
If you want to use a method in your License object you need to :
Call your WebService, obtain a service.License object, use it to create an instance of your local License object, after that you will have your 'local' License object with state (properties) filled by your WebService answer.
Otherwise i do not see why you would want to use a 'local' License object ?
You should not share the assembly between your web service and your client but instead create an instance of your License from your web service proxy types (should be found into service.x)
You need to create an instance from the webserviceproxy rather than from the asembly.
When you add a service reference to your webserice from the client it will generate proxy classes for you.Inside these you will have the License defined.use this to create an instance and pass it rather than referencing directly from your assembly.

How do I return a dynamically typed object in my C# web service?

I have a followup question to this question.
I'm writing a web service which dynamically calls other web services, using the WSProxy class found here.
Using WSProxy returns an object with a dynamic type, depending on the web service method called. For example, if I'm calling a method that returns...
<StateCodes>
<StateCode>
<Code>AL</Code>
<Name>Alabama</Name>
</StateCode>
<!-- and so on -->
</StateCodes>
then the object is of the type StateCodes[].
If I'm calling a method that returns ...
<GetVehicleMakes>
<VehicleMakes>
<Vehicle_Make_Code>00</Vehicle_Make_Code>
<Vehicle_Make_Description>Ford</Vehicle_Make_Description>
</VehicleMakes>
<VehicleMakes>
<Vehicle_Make_Code>01</Vehicle_Make_Code>
<Vehicle_Make_Description>Toyota</Vehicle_Make_Description>
</VehicleMakes>
<!-- and so on -->
</GetVehicleMakes>
then the object is of the type GetVehicleMakes[].
I can't declare a class type beforehand because the class type of the returned object is determined by the web service method called, and the web service method is determined at runtime. There are dozens of methods with different return types on the local service I'm testing against. I don't get to know the type of the returned object before runtime, because any method from any web service could be called.
When I try to return the object straight up, like so:
[WebMethod]
public object RunService(string webServiceAsmxUrl, string serviceName, string methodName, string jsonArgs)
{
WSDLRuntime.WsProxy wsp = new WSDLRuntime.WsProxy();
// Convert JSON to C# object.
JavaScriptSerializer jser = new JavaScriptSerializer();
var dict = jser.Deserialize<Dictionary<string,object>>(jsonArgs);
object result = wsp.CallWebService(webServiceAsmxUrl, serviceName, methodName, dict);
// This line produces the error.
return result;
}
I can insert a breakpoint at the return result line, and browse my result object. For example, when I call the StateCodes method, the result variable is the StateCodes[] array.
However, once return result runs, the XML parser won't have it.
System.InvalidOperationException: The type StateCodes[] may not be used in this context.
I've searched for answers, and I see terms like, "reflection" and "serialization" coming up, but I am very new to C# and don't know if these are what I want or how they work.
I'm using C# 3.5.
It looks like you need to return the xml that is returned from the service call. You can't return the object directly because the top-level service (the one that has a return type of object) is not generated at runtime; it is defined when its wsdl is consumed.
Long story short, you should change the return type of your top-level WebMethod to be string and serialize result manually in order to do what you want. Then the client (who presumably knows what they expect to get back from the service that they are requesting via webServiceAsmxUrl, serviceName, and methodName) can deserialize the result themselves.

Webservice C# constructor does not allow arguments?

Im trying to create a web services that takes some arguments in its constructor to save round trips, but i keep getting the error:
CS1729 "servicename" does not contain a constructor that takes '1' arguments
although when I try to create an instant locally (in the same project as the service) everything works fine... what gives?
web service:
public class ayyash : System.Web.Services.WebService {
private string _myname;
public ayyash (string myname) {
_myname = myname;
//Uncomment the following line if using designed components
//InitializeComponent();
}
}
consumption:
ayyash a = new ayyash("my name is ayyash");
output:
Compiler Error Message: CS1729: 'ayyash' does not contain a constructor that takes '1' arguments
The server side constructor is not called when you instantiate your client proxy. It is called when the server side object is created; that is, if and when a web service method is called.
Also worth nothing is that you cannot have instance members on a web service. You cannot accept "name" in the constructior and use it from other methods; you must send in "name" into each web service method as an argument. In short, web service "state" must be passed to the service via method arguments or a cookie (though using the latter will cause you problems if you move to WCF).
Just imagine that everytime you call a method on your proxy object, a new server side object is created and that method is called before the object is destroyed. This is not strictly true (the object can be pooled), but it will help you design your web services.
When the client is "instantiating" your web service it is not calling the constructor on your service. It is instantiating a local proxy object that represents your service. The proxy object generated by .NET only supports a default constructor. This is why you get a compiler error.
The reason why the local object works is that you are not actually calling a web service. You are simply instantiating a local object and then calling a method on it.
I think you need to change your approach to pass in all of the data required to the WebMethod. The typical approach with web services is to have a stateless service that accepts all of the data required to perform the requested operation.
For example:
[WebMethod]
public string DoSomething(string name, string otherData)
{
ayyash yourObject = new ayyash(name);
return yourObject.DoIt(otherData);
}
The default constructor will be called when the service host creates an instance in request to a service request message.
Why not get the default constructor to get the data it needs? You could delegate to the parameterised constructor.
public MyWebService : this(xxx) {}
What I mean is that the service host will always create an instance of your class (to handle the request via the default constructor. If you want to pass parameters to it you have a number of options:
In the Default constructor go off the locate the data it needs
Pass the data in the Request
Possibly (I'm not sure) extend/modify the asp.net request response pipe line to use a different service instance creation mechanism. This link has some further examples.
I believe that WCF will allow you to do this easily more easily. Also you can use the HTTPListener directly.

Categories

Resources