I'm developing a .NET 3.5 webservice using .asmx pages, but the fact that i cant use optional parameters in the GET and POST requests is making me think
in switch my application to WCF. But I didnt understand clearly how it works.
Can you show me how the below code would be if converted to WCF?
[WebService]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ToolboxItem(false)]
[ScriptService]
public class ws :WebService
{
#region WebMethods
//Parameters shoud be optional but it isnt possible in .asmx .NET 3.5
[WebMethod]
public XmlNode GetResult(string param1(=null), string param2(= null))
{
MyClass myClass = new MyClass();
//Get a xml string
string output = myClass.GetXmlString(param1, param2);
//Load this xml
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.LoadXml(output);
//Return this xml
return xmlDocument.DocumentElement;
}
#endregion
}
WSDL cannot describe optional parameters, so it wouldn't matter if you are using ASMX or WCF contracts, the actual semantics of using optional parameters is redundant (they are still classed as required parameters - i.e. like all parameters).
Related
I have an XML file which starts something like this:-
<?xml version="1.0" encoding="UTF-8"?>
<Deal xmlns="http://schemas.datacontract.org/2004/07/DealioCapLinkLib.Dealio.Models" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<AccountingDate>2019-09-30</AccountingDate>
When I try to convert this object to XML like below, I get an error:-
private static void Prod_Error_Test()
{
string prodRequestXml = File.ReadAllText("ProdXml.xml");
var serializer = new XmlSerializer(typeof(Service.Deal));
Service.Deal request ;
var reader = new StringReader(prodRequestXml);
request = (Service.Deal)serializer.Deserialize(reader);
}
The Error Message is "There is an error in XML document (2, 2).". The Inner Exception Message is "<Deal xmlns='http://schemas.datacontract.org/2004/07/DealioCapLinkLib.Dealio.Models'> was not expected."
Service.Deal is a WCF Proxy.So I may not be able to add any attributes. Can anyone suggest what to do here ?
Being a WCF proxy doesn't preclude adding attributes; in particular, it is usually a partial class, which means you can have your own separate file, with:
namespace Service
{
[XmlRoot("Deal", Namespace = "http://schemas.datacontract.org/2004/07/DealioCapLinkLib.Dealio.Models")]
partial class Deal {}
}
But ultimately: if the type doesn't conveniently fit the XML: stop fighting it - create a new separate type that fits the XML and works well with XmlSerializer, and then map between the two types in your own code.
I’m trying to consume a webservice in .NET Core 2.0 by using SOAP. The client for the webservice was generated with the “Connected Service”-feature of Visual Studio.
Now I have the problem, that the webservice needs in the request the (first) line with the encoding-Attribute:
<?xml version="1.0" encoding="utf-8"?>
I’ve tried many different ways to write this line in the output-XML, but nothing works.
First approach:
I added a new endpoint behavior (by implementing IEndpointBehavior) to the client with using a customized message inspector (by implementing IClientMessageInspector). Via debugging I found out, the message object contains the said line. But by writing the outgoing XML to the webservice, the line is missing.
Second approach:
I wrote a customized message encoding binding element with a wsdl export extension (by using MessageEncodingBindingElement & IWsdlExportExtension) . This binding element uses a customized MessageEncoder where the encoding is set explicitly. I added the binding to the generated client.
Here are some .net 4.6 code snippets:
// Binding for the client
TextMessageBindingElement textBindingElement = new TextMessageBindingElement();
textBindingElement.Encoding = "utf-8";
textBindingElement.MessageVersion = MessageVersion.Soap11;
textBindingElement.MediaType = "text/xml";
bindingElements.Add(textBindingElement);
CustomBinding binding = new CustomBinding(bindingElements);
// Customized Message Binding Element for encoding
public class TextMessageBindingElement : MessageEncodingBindingElement,
IWsdlExportExtension {
public override MessageVersion MessageVersion { get; set; }
public string Encoding { get; set; }
...
public override MessageEncoderFactory CreateMessageEncoderFactory() {
return new TextMessageEncoderFactory(MediaType, Encoding, MessageVersion);
}
void ExportContract(WsdlExporter exporter, WsdlContractConversionContext context) {
}
void ExportEndpoint(WsdlExporter exporter, WsdlEndpointConversionContext context) {
TextMessageEncodingBindingElement mebe = new TextMessageEncodingBindingElement();
mebe.MessageVersion = this.msgVersion;
((IWsdlExportExtension) mebe).ExportEndpoint(exporter, context);
}
}
In .NET 4.6 this works, but .NET Core 2.0 doesn’t support IWsdlExportExtension. I’ve searched for alternatives, but haven’t found anything yet.
Please, can anybody help me?
I need to build a web service that accepts XML data.
The XML will send as the below example :
<Person>
<LegalName>
<FirstName>Ralph</FirstName>
<LastName>Anderson</LastName>
<PhoneticFirstName>rah-lf</PhoneticFirstName>
</LegalName>
<SSN>122-34-1232</SSN>
<Demographics>
<Sex>male</Sex>
<Height>502</Height>
</Demographics>
<DriversLicense>
<DriversLicenseNumber>1234</DriversLicenseNumber>
<IssuingState>CA</IssuingState>
</DriversLicense>
My understanding is I need to write something like this:
public Service () {
[WebMethod]
public void CreateRecord(XmlDocument newRecord)
{
// do stuff
}
}
How I can do that?
You could try to understand how it works and find a nice artical here:
https://msdn.microsoft.com/en-us/library/hh534080.aspx
I have a C# Web Service that is serializing my simple class:
[Serializable]
[XmlInclude(typeof(Bitmap))]
[XmlTypeAttribute(Namespace = "http://tempuri.org/")]
public class Class1
{
private static Bitmap _myImage = new Bitmap(#"C:\WebApplication1\ClassLibrary1\Untitled.png");
public Bitmap MyImage
{
get { return _myImage; }
set
{
_myImage = value;
}
}
}
Here's the asmx.cs code that does the serialization:
[WebMethod]
public string HelloWorld()
{
var c = new Class1();
XmlSerializer serializer = new XmlSerializer(typeof(Class1));
return XMLSerializer(c);
}
public string XMLSerializer(object pObject)
{
try
{
XmlSerializer xs = new XmlSerializer(pObject.GetType());
using (StringWriter stream = new StringWriter())
{
xs.Serialize(stream, pObject);
stream.Flush();
return stream.ToString();
}
}
catch (Exception ex)
{
return ex.ToString();
}
}
Looks prety straight forward. However, the XML generated by the XmlSerializer is producing and error when I try to DeSerialize it.
{"There is an error in XML document (5, 5)."}
{"Parameter is not valid."}
When I try to load the generated XML into IE I get this error.
Switch from current encoding to specified encoding not supported. Error processing resource 'file:///C:/Users/mhall15/Deskt...
<?xml version="1.0" encoding="utf-16"?>
Here's the generated XML:
<?xml version="1.0" encoding="utf-16"?>
<Class1 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<MyImage xmlns="http://tempuri.org/">
<Palette />
</MyImage>
</Class1>
Any ideas what's going on?
During the serialization, replace "encoding="utf-16" with "encoding="utf-8"" and that will cut it. The source of the problem - I'm not sure, but I've ran into it numerous times, and that's how I dealt with it.
That's how to deal with the IE issue.
The deserialization should be amongst these lines. I'm posting the kind of arbitrary code I normally use:
public static object DeserializeFromXML<T>(string _input)
{
object _temp = Activator.CreateInstance<T>();
Type expected_type = _temp.GetType();
_temp = null;
XmlSerializer serializer = new XmlSerializer(expected_type);
StringReader stringWriter = new StringReader(_input);
object _copy = serializer.Deserialize(stringWriter);
return _copy;
}
In the above example, I'm using templating for reusability sake. You should be able to call the method by saying DeserializeFromXML < Class1 >(_xml_input) where xml input is the string. That will force the compiler to use the definition of the given class to deserialize the XML input. That way you wouldn't even have to change the encoding in the serialization. If it's also a case where you may or may not know the data type to deserialize with, you can use a strategy design pattern where you register the root type of the XML with it's associated generic type. Later on you can reference that registry and arbitrarily deserialize any XML input as long as the root type is registered. It's a trick i normally use as well. If more is needed on this, let me know, and I'll explain in detail.
In addition,if you are running IE 9, the new update to IE 9 makes it difficult to view XML. Press F12 - go to developer tools and change your browser mode to run as IE 8 instead of IE 9.
Is it possible to create an C# web service which returns multiple strings, without generating a complex type? (Because my client can't handle complex types and I need to return exactly 2 strings with the names: "wwretval" and "wwrettext")
I've already tried to create a struct or a class or do it with out params, but it always generated a complex type in the WSDL.
Could you send them as an XML blob or, failing that, pack the strings into a single string separater by a nonprinting character such as \n then split them at the other end?
The latter is not exactly elegant but could work.
Since you can't change the client perhaps you can fool it by forcing Soap to use RPC mode with literal binding:
namespace WebTest
{
public struct UploadResponse
{
public string wwretval;
public string wwrettext;
}
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.None)]
[System.ComponentModel.ToolboxItem(false)]
public class Service1 : System.Web.Services.WebService
{
[SoapRpcMethod(ResponseElementName = "UploadResponse",Use=SoapBindingUse.Literal)]
[WebMethod]
public UploadResponse Upload()
{
UploadResponse ww = new UploadResponse();
ww.wwretval = "Hello";
ww.wwrettext = "World";
return ww;
}
}
}
That will generate a response with two strings inside of an UploadResponse element. You can then generate a fake wsdl as described here: How do I include my own wsdl in my Webservice in C#
You can send the 2 string separated by a ';' . And the client split the string.
(Cowboy coder from hell)