Search code examples
c#wcfasynchronouscancellation-tokensoapcore

SoapCore WCF C# program using XmlSerializer doesn't create the WSDL with async methods with CancellationToken


I have an issue in async WCF service using SoapCore in .Net 6 using a cancellation token and XmlSerializer serializer.

The detailed WCF application is as follows:

  • WCF service in C# .Net Core 6 using SoapCore NuGet package using SoapSerializer.XmlSerializer serializer
  • I created an async method that has the [OperationContract] attribute with a CancellationToken parameter
  • I try to get the WSDL using the URL https://localhost:7026/Services.svc?WSDL and it fails because of the CancellationToken with the exception ArgumentException: .NET type CancellationToken cannot be resolved into XML schema type (CancellationToken has namespace starting with System (System.Threading.CancellationToken), is a structure (value type), and is categorized by SoapCore code as very similar to bool, int, long, ... and tries to generate an XML for it and it fails)
  • I tried adding the [XmlIgnore] attribute to the parameter CancellationToken of the method having the [OperationContract] attribute and it doesn't work
  • [MessageContract(IsWrapped = false)] cannot be added to parameters of methods

Note: This works with SoapCore with SoapSerializer.DataContractSerializer serializer, but the generated WSDL is bigger enumerating many basic types that I don't use and I want to use SoapSerializer.XmlSerializer if possible.

Program.cs code:

using Microsoft.Extensions.DependencyInjection.Extensions;
using SoapCore;

namespace TestSoapCore;

public static class Program
{
    public static void Main(string[] args)
    {
        var builder = WebApplication.CreateBuilder(args);
        builder.Services.AddSoapCore();
        builder.Services.TryAddSingleton<MyService>();
        builder.Services.AddMvc();

        var app = builder.Build();
        app.UseRouting();
        app.UseEndpoints(endpoints =>
        {
            endpoints.UseSoapEndpoint<MyService>(
                "/Services.svc",
                new SoapEncoderOptions(),
                SoapSerializer.XmlSerializer
                // This works with SoapSerializer.DataContractSerializer but I prefer SoapSerializer.XmlSerializer if possible
            );
        });
        app.Run();
    }
}

Contract.cs code:

using System.Runtime.Serialization;

namespace TestSoapCore;

[DataContract]
public class Contract {
    [DataMember]
    public string? TestProperty { get; set; }
}

MyService.cs code:

using System.ServiceModel;
using System.Xml.Serialization;

namespace TestSoapCore;

[ServiceContract]
public class MyService
{
    [OperationContract]
    public async Task<string> Test(
        Contract contract,
        // [MessageContract(IsWrapped = false)] cannot be added to parameters
        [XmlIgnore] // This doesn't work
        CancellationToken cancellationToken)
    {
        cancellationToken.ThrowIfCancellationRequested();

        return contract?.TestProperty + "2";
    }
}

Full exception while getting the WSDL at https://localhost:7026/Services.svc?WSDL when SoapSerializer.XmlSerializer serializer is used: Exception while getting the WSDL

How the WSDL works with SoapSerializer.XmlSerializer serializer without any CancellationToken (but I want the CancellationToken for async methods, it is better to have it): WSDL with SoapSerializer.XmlSerializer that is not bloated but without CancellationToken

How the WSDL is bloated and has many basic types I don't use when SoapSerializer.DataContractSerializer serializer is used (that's why I still prefer SoapSerializer.XmlSerializer if possible):

  • Part 1: WSDL with SoapSerializer.DataContractSerializer part 1
  • Part 2: WSDL with SoapSerializer.DataContractSerializer part 2
  • Part 3: WSDL with SoapSerializer.DataContractSerializer part 3
  • Part 4: WSDL with SoapSerializer.DataContractSerializer part 4

Solution

  • Because the CancellationToken is not working very well with WCF using SoapCore (SoapSerializer.XmlSerializer serializer doesn't generate the WSDL because of CancellationToken and SoapSerializer.DataContractSerializer serializer puts the CancellationToken as an object that needs to be sent with many properties and their types) I ended up removing the CancellationToken entirely and I used the SoapSerializer.XmlSerializer to have less data (WSDL not bloated with all the unused types, many pages of useless data).

    PS: This is how the CancellationToken looks with SoapCore and SoapSerializer.DataContractSerializer serializer (not very nice..): CancellationToken in WSDL