I am writing a "universal" client for Web services, and have hit an unexpected problem. I generate the code for the client dynamically by retrieving the Web services WSDL, and using the following (simplified a little) code to generate the client code:
ServiceDescription serviceDescription = ServiceDescription.Read(xmlTextReader(WSDL));
ServiceDescriptionImporter descriptionImporter = new ServiceDescriptionImporter();
descriptionImporter.ProtocolName = "Soap";
descriptionImporter.Style = ServiceDescriptionImportStyle.Client;
CodeCompileUnit codeCompileUnit = new CodeCompileUnit();
CodeDomProvider codeDomProvider = CodeDomProvider.CreateProvider("CSharp");
codeDomProvider.GenerateCodeFromCompileUnit(codeCompileUnit, Console.Out, new CodeGeneratorOptions());
I am testing this using a simple WCF Web service that exposes two methods:
[OperationContract]
int GetInteger();
[OperationContract]
string GetString();
If I examine the client-side generated code, then I can see that the GetString() returns a string, but the GetInteger() method returns void! I assume that this is something to do with value and reference types. Is there some way to force the code generator to make the GetInteger() method return an int?
Returning an int over WCF should not be a problem.
Check the code that produces the client side generated code.
The hack to get around the problem would be to return an object that had a single property that was an int.
From various experiments, I believe that my problem is an inherent limitation of using the ServiceDescriptionImporter to generate the client code. I am going to try to "upgrade" to using the System.ServiceModel.Description.WsdlImporter and System.ServiceModel.Description.ServiceContractGenerator framework, in the hopes that improves things.
Related
We recently had to upgrade our Win 8.1 store app to Win 10. Part of that change was modifying our NetTcpBindings to instead be BasicHttpBindings for file uploads since UWP does not currently support NetTcpBindings. Our issue is that when the client calls the UploadFileMethod on the proxy class, we intercept the message before it is sent to the server so we can apply headers that are used later as follows:
public async Task UploadFileAsync(RemoteFileInfo request)
{
using (new OperationContextScope(this.InnerChannel))
{
string nameSpace = #"http://tempuri.org";
OperationContext.Current.OutgoingMessageHeaders.Add(MessageHeader.CreateHeader("FileName", nameSpace, request.FileName));
OperationContext.Current.OutgoingMessageHeaders.Add(MessageHeader.CreateHeader("Length", nameSpace,
request.Length));
await Channel.UploadFileAsync(request);
}
}
This used to work fine when we were using NetTcpBinding but since we switched to BasicHttpBinding that code is now throwing an exception on the line:
await Channel.UploadFileAsync(request);
With the exception reading:
This message cannot support the operation because it has been written.
After reading up on this exception it appears that we cannot mess with the request object at all before it is sent to the server when using BasicHttpBinding. If that is the case, how can we add OutgoingMessageHeaders to the message using properties of the request itself?
Edit: The proxy class is created as follows:
var imageProxy = new RTMImageServiceProxy(globalContext.Win10UploadBinding,
globalContext.ImageEndpointAddress);
Where Win10UploadBinding is configured as so:
BasicHttpBinding win10BasicBinding = new BasicHttpBinding();
win10BasicBinding.Security.Mode = BasicHttpSecurityMode.None;
win10BasicBinding.TransferMode = TransferMode.Streamed;
win10BasicBinding.SendTimeout = new TimeSpan(0, 0, 2, 0);
win10BasicBinding.MaxReceivedMessageSize = 2147483647;
this.win10UploadBinding = win10BasicBinding;
and globalContext is just a static class I used to store commonly-used variables.
Apparently it turns out that once written cannot be altered so create a copy with adjusted headers. Equivalent issue was brought up here.
Anyway, I encourage you to create custom message inspector: class deriving IClientMessageInspector, as far as client is concerned. It provides separation between method being invoced and headers being adjusted.
I'm trying to perform some actions on a remote server using the XML-RPC .NET library and C#. I have no prior experience using this protocol but most examples seemed pretty straight forward. But the server I'm trying to communicate with seems to parse commands slightly different than most examples I've seen.
All calls are made using a 'perform_actions' function and it expects a list of action(s) along side with it as parameter. Fortunately there's a pretty decent documentation with some code samples included but these examples are done in Ruby/Perl with which I have no experience. I've tried translating these to C# with which I believe I'm on the right path but I'm consistently getting the error"Server returned a fault exception: [400] Invalid request: expected list of actions."
My current code
[XmlRpcUrl("https://DOMAIN/admin/rpc")]
public interface iFace : IXmlRpcProxy
{
[XmlRpcMethod("perform_actions")]
XmlRpcStruct[] perform_actions(XmlRpcStruct struc);
}
public void GetData()
{
XmlRpcStruct actions = new XmlRpcStruct();
actions.Add("name", "registrations.accounts.list");
iFace proxy = XmlRpcProxyGen.Create<iFace>();
proxy.Credentials = new NetworkCredential("USERNAME", "PASSWORD");
XmlRpcStruct[] response = proxy.perform_actions(actions);
}
And here is a Ruby example from the API documentation which I was trying to replicate which is functional
require 'xmlrpc/client'
url = 'https://user:passwd#qmanage.example.com/admin/rpc'
c = XMLRPC::Client.new_from_uri(url)
# Call the action to list the access groups.
ags = c.call('perform_actions', [{
'name' => 'network.accessgroups.list',
'args' => {}
}])
The server doesn't really seem to recognize the XmlRpcStruct I'm sending as the error seems to complain about not receiving a list of actions. (I receive the same error if I send no parameter). However if I change the XmlRpcStruct to a regular string array it will complain about expecting a struct instead so the data isn't ignored entirely.
Is anyone able to help me in the right direction with my problem or does anyone know why this error is returned?
Finally managed to figure out my dilemma. Seems I had to pass an array of XmlRpcStruct's rather than just singular XmlRpcStruct, the following solved my problem:
XmlRpcStruct[] actions = new XmlRpcStruct[1];
XmlRpcStruct action = new XmlRpcStruct();
action.Add("name", "registrations.accounts.list");
actions[0] = action;
I just passed actions as parameter to the perform_actions function.
I have a series of self-hosted WCF services (using netTcpBinding) that I want to enhance by using the fantastic protobuf-net serializer.
I configured both the client and the service endpoints with the custom behavior extensions as instructed in the documentation of the ProtoEndpointBehavior class (see here). My tests ran fine from the very first try, however, I'm very skeptical of WCF-stuff running fine at the very first try ;)
Is there a simple way in which I can assert that the default DataContractSerializer was replaced by the XmlProtoSerializer?
I would really favor a test that can be also coded as part of a unit test. I wouldn't like the protobuf-net library to be inadvertently disabled by careless tampering of the .config file.
If you call your service in wcf test client, you will see < proto/> tag in the body of response
If you configure your client to use proto behaviour and call service with "inadvertently disabled protobuf", your answer will be null because of different serializers. You can check it in your test
var address = new EndpointAddress( url );
var binding = GetBinding( address.Uri );
var factory = new ChannelFactory<TService>( binding, address );
factory.Endpoint.EndpointBehaviors.Add( CreateProtobufEndpointBehavior() );
var client = factory.CreateChannel();
var answer = client.GetSomeInt();
AssertAnswerIsNotNull(answer);
Ok, its been a while since I've worked with a Web References. I need a refresher. I think I have about 80% of the code I need to get a response going but I'm missing something. Maybe you can help me :)
Given:
A web method called GetSomething in the list of methods when pointing to a .wsdl url.
This produces a few classes/objects:
GetSomethingRequest
GetSomethingCompletedEventHandler
GetSomethingCompletedEventArgs
myComplexType
Which I use to create this code:
void someMethodToTestResponse()
{
GetSomethingRequest request = new GetSomethingRequest();
// fill in the request
request.myComplexType.Property1 = "Blah";
request.myComplexType.Property2 = "Kachoo";
GetSomethingCompletedEventHandler handler = GetSomethingCompleted_Response;
//.... ok now what?
//handler.Invoke(???)
// at this point I'm supposed to send an object for source (request maybe?)
// and a new instance of GetSomethingCompletedEventArgs but that class is
// asking for stuff that makes me think that is not the right idea.
}
void GetSomethingCompleted_Response(object source, GetSomethingCompletedEventArgs args)
{
// get the result
var result = args.Result;
}
What am I doing wrong? What am I missing? Thanks in advance.
You don't need web service source codes. The web service can be implemented in Java. Creating service reference woks the same, as we really don't know what is on the other side.
So, try Add Service Reference in VS2008 and enter the url to working web service. VS will examine the wsdl on server and generate needed classes for you.
From than on, you just call the service as some ordinary method call. Meaning you don't have to fiddle with requests and http and such details. All that is hidden from you. Except in app.config where many WCF settings can be changed.
Ok, I figured out that I needed to find a Service type class. See this SO Post where it mentions:
private com.nowhere.somewebservice ws;
The issue was that the class they provide wasn't intellisensing for me and I figured it wasn't what I was looking for.
Here is how I would solve my problem:
blah.webservice.SomeMainServiceClass service = new SomeMainServiceClass();
GetSomethingRequest request = new GetSomethingRequest();
// fill in the request
request.myComplexType.Property1 = "Blah";
request.myComplexType.Property2 = "Kachoo";
object myResponse = service.GetSomething(request);
I am trying to consume the .net webservice from cold fusion. Methods having simple types working fine. But i am having problems with one particular method which accepts byte[] array as input.
Below the sample webmethod declaration
[WebMethod]
public AVStatus ScanStream(byte[] fileObject)
{
// code
}
and the cold fusion code consuming this service is
<cffile action="readBinary" file="#FileName#" variable="filedata">
<cfset b64file = #toBase64(filedata)#>
<cfinvoke webservice = "http://xxx/scanservice.asmx?wsdl"
method = "ScanStream"
returnVariable = "result">
<cfinvokeargument name="fileObject" value="#b64file#" />
</cfinvoke>
This always leads to this error Web service operation ScanStream with parameters cannot be found.
can someone help me out this?
It seems that the binary data has been exposed as bas64 string in the coldfusion while byte[] is exposed by the service as an XML array (of bytes).
Change the ScanStream (if you can) to accept a string, if web service is not yours you could convince owners to provide another method which accepts string and uses Convert.FromBase64String to change to byte array.
Webservices are remote, not public. Public allows access by other CF classes and pages. Change public to remote, and you should be able to "see" your webservice.