Soap WebService Server with .NET6 and XML attributes - c#

I'm migrating a .NET Framework SOAP Web Service (Server Side) to a new .NET 6 project.
I used DataContract and DataMember with no issues until I reached a WS which had to return XML attributes.
Then I read the official documentation but was not able to find a way to return attributes inside my XML elements.
They suggest to use XmlSerializer and the "XmlAttribute" attributes, but they seems to be ignored by .NET 6.
Am I forced to roll it back to .NET Framework or is there anything I can do?
Here is a simple example that's not working:
Of course if I switch it back to DataModel it works, but I am not able to have XML attributes.
What I want to achieve is
<BankingTransaction operation="opName">
<amount>100</amount>
</BankingTransaction>
THE INTERFACE
[ServiceContract]
[XmlSerializerFormat]
public interface IBankingService
{
[OperationContract]
public BankingTransaction ProcessTransaction();
}
THE SERVICE IMPLEMENTATION
public class BankingService: IBankingService
{
public BankingTransaction ProcessTransaction()
{
BankingTransaction bt = new BankingTransaction();
bt.amount = 1000;
bt.Operation = "Test";
return bt;
}
}
THE MODEL
public class BankingTransaction
{
[XmlAttribute]
public string Operation;
[XmlElement]
public int amount;
}
Thanks
A PIECE OF THE program.cs file
builder.Services.TryAddSingleton<IBankingService, BankingService>();
app.UseSoapEndpoint<IBankingService>("/Service.asmx", new SoapEncoderOptions());

Related

Overriding a Generated Partial Class

I have imported a third-party WSDL (via Service Reference) into my Console Application project in order to send and receive data through Web Services. In order to get this to function appropriately, I have had to add some code to the Reference.cs file associated to the Web Service. While this works, if an update is made to the WSDL, and I re-import/generate that Service Reference, that work-around code will go away.
In order to get around this, I have saved the necessary code-changes to an external text file saved within the project.
I'm curious if anyone knows of a way that I could write these changes into a their own separate class, outside of the Service Reference, and yet, still be referenced by the Service Reference, thus using the "correct" code needed to send/receive from the Web Service.
I have two classes (not included in the generated code) that I am able to reference in the generated code after separating them into their own .cs file and referencing the namespace used by the Service Reference.
What I would like to do, if possible, is the following:
Overall Goal:
Add custom code to code generated by importing a third-party WSDL as a Service Reference, that way when the WSDL is updated by the third-party, another developer would not have to necessarily remember to dive into the Reference.cs file of the Service Reference, and replace/add specific code.
To achieve this goal, I need to be able to:
Replace an existing property and associated field of the generated
partial class, with a customized version (see Snippet #1 below).
Replace an existing generated partial class with a customized version of the class, having a different attribute definition and slightly different property/field definitions.
Snippet #1
Replace the following:
private byte[] bulkExchangeFileField;
[System.Xml.Serialization.XmlElementAttribute(Namespace = "urn:us:gov:treasury:irs:common", DataType = "base64Binary", Order = 0)]
public byte[] BulkExchangeFile
{
get { return this.bulkExchangeFileField; }
set
{
this.bulkExchangeFileField = value;
this.RaisePropertyChanged("BulkExchangeFile");
}
}
with this version of the properties/fields that worked once I altered the generated code:
private BulkExchangeFileType bulkExchangeFileField;
[System.Xml.Serialization.XmlElementAttribute(Namespace = "urn:us:gov:treasury:irs:common", Order = 0)]
public BulkExchangeFileType BulkExchangeFile
{
get { return this.bulkExchangeFileField; }
set
{
this.bulkExchangeFileField = value;
this.RaisePropertyChanged("BulkExchangeFile");
}
}
Use extension methods and/or overload the properties in an inhered class, so your code will not be replaced.
To overload the properties you just need to declare it with the word new before public like in : new public BulkExchangeFileType BulkExchangeFile, so when you use the object it will call your properties instead the ones defined by the web service
and here is how to create extention methods https://msdn.microsoft.com/library/bb383977.aspx
class Program
{
static void Main(string[] args)
{
InheredClass test = new InheredClass(); // Do this
BaseClass test2 = new InheredClass(); // don't do this
Console.WriteLine(test.MyProperty.GetType());
Console.WriteLine(test2.MyProperty.GetType());
Console.Read();
}
class BaseClass
{
public int MyProperty { get; set; }
}
class InheredClass : BaseClass
{
new public decimal MyProperty { get; set; }
}
}

Looking for a workaround to serializing a method or constant

Apparently my education has failed me, because I didn't realize that methods in C# cannot be serialized. (Good to know.)
I am trying to create a WCF service that returns a simple class I created. The problem is that this simple class contains methods that I want to expose, and the caller of my service won't have any access to them (assuming they won't have a .dll containing the class declaration).
public class Simple
{
public string Message { get; set; }
private const string _Hidden = "Underpants";
public string Hidden
{
get { return _Hidden; }
}
public string GetHidden()
{
return _Hidden;
}
}
I set up a WCF service (let's call it MyService) to return an instance of my Simple class. To my frustration, I'm only getting a partial build of my class back.
public void CallService()
{
using (var client = new MyService.Serviceclient())
{
Simple result = client.GetSimple();
string message = result.Message; // this works.
string hidden = result.Hidden; // this doesn't.
string fail = result.GetHidden(); // Underpants remains elusive.
}
}
Is there any type of workaround where I'm able to set up a property or method on my class that will be accessible to whomever calls my service? How does one handle constants or other methods that are set up in a class that only exists in a service?
Typically you would create three different projects.
1. Service project
2. Client project
3. Data project
The Data project contains only the data classes - no application code. The methods and constants in these data classes should be independent of the Service/Client projects.
The Data project is included as a reference in both the Service and Client projects so that serialization and deserialization happen against the same binary - and you get to retain your constants/methods/etc.
The downside here is that all your clients will either have to be .NET apps, or you will have to provide different data libraries for each platform you wish to support.
As far as I know the only things that can be returned in a WCF service are primitives or a class with public properties that have a get method on them. From a high level WCF exists to allow you to specify a contract between the client and the server that it in theory transportation agnostic (ie you can swap out an HTTP endpoint for a netTcp endpoint and the service will function the same way from a contractual level).
The question to answer then is what data are you trying to pass back in this service call. If it's an object called simple with the data points of Message and Hidden then I would advise creating a data class called Simple that has those values as properties:
[DataContract]
public class Simple
{
[DataMember]
public string Hidden { get; set; }
[DataMember]
public string Message { get; set; }
}
When the client receives the response back Message and Hidden will be populated with whatever you have set their values to on the server side.
The DataMember attribute can only be used on properties and fields. This means that a WCF response can only serialize these types.
If you really want to only use the const in your WCF contract You could convert it to a field and place the DataMember attribute on it:
public class Simple
{
[DataMember]
public string Message { get; set; }
[DataMember]
public const string Hidden = "Underpants";
}
To be able to do this the field must be accessible (public).
Add the DataMember attribute to your property. To do so, you must have both a get and a set defined.
[DataMember]
public string Hidden
{
get { return _Hidden; }
set { }
}
technically you could do
public class thingToSerialize{
public Func<ArgType1,ArgType2...,ReturnType> myFunction{get;set;}
}
and then assign it a lambda that takes the arguments and returns the return type
before serializing

How to rename xml serialization on web service?

I have a web service written in C# and on this project I added a model called ProjectDTO. I have a web service that returns some objects of this class and I would like that my web service return a node called Project in my xml result and not ProjectDTO, how can I do this?
I tried to add some attributes on my ProjectDTO class like XmlRoot, XmlElement but it does not work.
Thanks
Edits
public class ProjectDTO {
//some properties
}
my web service (.asmx file.. it's a simple webservice from asp.net 2.0) method:
[WebMethod]
public ProjectDTO[] GetProjects();
My output xml:
<ArrayOfProjectDTO ...>
<ProjectDTO>
<Id>...</Id>
<Nome>...</Nome>
</ProjectDTO>
</ArrayOfProjectDTO>
I would like to rename all places where is 'ProjectDTO' to 'Project' on this xml output, is that possible?
Thanks
I knew I had programmed something similar before, it just took me a while to remember.
Here is the format you're looking for:
public class WebService : System.Web.Services.WebService {
[WebMethod]
[return: XmlRoot(ElementName = "Projects")]
public ProjectDTO[] HelloWorld()
{
return new ProjectDTO[] { new ProjectDTO(), new ProjectDTO(), new ProjectDTO(), };
}
}
[XmlType(TypeName = "Project")]
public class ProjectDTO
{
public string Blah { get; set; }
}
The key is the XmlRootAttribute and the XmlTypeAttribute.

LINQ to JSON in .net 4.0 Client Profile

How would I go about about using LINQ to JSON in the .net 4 Client Profile in C#. I'd like to query certain json responses as shown in msdn blog post without having to write out a contract (datacontract, servicecontract, etc). I really only need to query(read) the response, I don't need to modify the json response. (Also would a datacontract be faster than LINQ to JSON?)
Alternatively I could use XML or the full .net 4 framework, but I'm hoping that this can be avoided. I can use external libraries if it's better than installing the whole framework.
JSON.net is quite popular and seems to be what you're after.
If your service is used by Ajax (jQuery) clients, you will get the best performance by using JSON.
Another recommendation; in order to get rid of the same domain policy, I recommend you to enable crossDomainScriptAccessEnabled functionality:
<webHttpBinding>
<binding name="myHttpBinding" crossDomainScriptAccessEnabled="true" />
</webHttpBinding>
Regarding the DataContract; in your scenario, a DataContract is not really needed.
Example code:
Your Service:
[ServiceContract]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class BlogService {
[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Json)]
public List<Article> GetBlogArticles()
{
return Article.GetDummyArticles.ToList();
}
}
Article Class (excerpt):
public class Article {
public string Title { get; set; }
public string Body { get; set; }
public static IEnumerable<Article> GetDummyArticles() {
yield return new Article { Title = "Article 1", Body = "sdlkfjsdlkfjskl" };
yield return new Article { Title = "Article 2", Body = "sfsfsdfd23434wfdfsfdfkfjskl" };
}
}
For your scenario I actually can't find a reason to use any (3rd-party) library since WCF4 already contains native support for JSON with or without Padding.

WCF REST Starter Kit not filling base class members on POST

I have a WCF REST Starter Kit service. The type handled by the service is a subclass of a base class. For POST requests, the base class members are not correctly populated.
The class hierarchy looks like this:
[DataContract]
public class BaseTreeItem
{
[DataMember]
public String Id { get; set; }
[DataMember]
public String Description { get; set; }
}
[DataContract]
public class Discipline : BaseTreeItem
{
...
}
The service definition looks like:
[WebHelp(Comment = "Retrieve a Discipline")]
[WebGet(UriTemplate = "discipline?id={id}")]
[OperationContract]
public Discipline getDiscipline(String id)
{
...
}
[WebHelp(Comment = "Create/Update/Delete a Discipline")]
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "discipline")]
public WCF_Result DisciplineMaintenance(Discipline discipline)
{
...
}
Problem: While the GET works fine (returns the base class Id and Description), the POST does not populate Id and Description even though the XML contains the fields.
Sample XML:
<?xml version="1.0" encoding="utf-8"?>
<Discipline xmlns="http://schemas.datacontract.org/2004/07/xxx.yyy.zzz">
<DeleteFlag>7</DeleteFlag>
<Description>2</Description>
<Id>5</Id>
<DisciplineName>1</DisciplineName>
<DisciplineOwnerId>4</DisciplineOwnerId>
<DisciplineOwnerLoginName>3</DisciplineOwnerLoginName>
</Discipline>
Thanks for any assistance.
I could not solve the problem using a DataContractSerializer. I switched to using the XMLSerializerFormat and everything worked fine. In fact, the capabilities of the XMLSerializer are so much better that for purely XML work, it is probably better to use the XMLSerializer in all cases.

Categories