How to Eliminate Nested XML Issues in ASP.NET Core 6.0 SOAP Services
While creating a SOAP API in ASP.NET Core 6.0 with SoapCore, I ran into a problem: my XML response had an extra layer that shouldn’t be there. The system using the API couldn’t work with this additional nesting.
Looking for solutions in various StackOverflow discussions and even a past GitHub issue, nothing seemed to work.
So, the decision was made to try something else - CoreWCF.
To illustrate the impact of our changes, let’s compare the SOAP messages before and after the transition.
With SoapCore, our configuration was:
// Program.cs
using SoapCore;
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
builder.Services.AddSoapCore();
builder.Services.AddScoped<MyService>();
WebApplication app = builder.Build();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.UseSoapEndpoint<MyService>(
"/Service.asmx",
new SoapEncoderOptions(),
SoapSerializer.DataContractSerializer);
});
app.Run();
// MyService.cs
using System.ServiceModel;
[ServiceContract]
public interface IMyService
{
[OperationContract]
MyResponse MyRequest(MyRequest myRequest);
}
public class MyService : IMyService
{
public MyResponse MyRequest(MyRequest myRequest)
{
return new()
{
OutputMessage = "Hello world"
};
}
}
// MyRequest.cs
using System.Runtime.Serialization;
[DataContract]
public class MyRequest
{
[DataMember]
public string InputMessage { get; set; }
}
// MyResponse.cs
using System.Runtime.Serialization;
[DataContract]
public class MyResponse
{
[DataMember]
public string OutputMessage { get; set; }
}
And our SOAP response had an extra element, MyRequestResult
, which was causing issues.
// SOAP response
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<s:Body>
<MyRequestResponse xmlns="http://tempuri.org/">
<MyRequestResult xmlns:d4p1="http://schemas.datacontract.org/2004/07/ExampleApi" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<d4p1:OutputMessage>Hello world</d4p1:Message>
</MyRequestResult>
</MyRequestResponse>
</s:Body>
</s:Envelope>
We made a few changes:
// Program.cs
using CoreWCF;
using CoreWCF.Channels;
using CoreWCF.Configuration;
using CoreWCF.Description;
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
builder.Services.AddScoped<MyService>();
builder.Services.AddServiceModelServices();
builder.Services.AddServiceModelMetadata();
WebApplication app = builder.Build();
app.UseServiceModel(configure =>
{
configure.AddService<MyService>()
.AddServiceEndpoint<MyService, IMyService>(
new BasicHttpBinding(BasicHttpSecurityMode.Transport),
"/Service.asmx");
ServiceMetadataBehavior serviceMetadataBehavior = app.Services.GetRequiredService<ServiceMetadataBehavior>();
serviceMetadataBehavior.HttpsGetEnabled = true;
});
app.Run();
// MyService.cs
using CoreWCF;
[ServiceContract]
public interface IMyService
{
[OperationContract]
MyResponse MyRequest(MyRequest myRequest);
}
public class MyService : IMyService
{
public MyResponse MyRequest(MyRequest myRequest)
{
return new()
{
OutputMessage = "Hello world"
};
}
}
We changed our data contracts to message contracts:
// MyRequest.cs
using CoreWCF;
[MessageContract]
public class MyRequest
{
[MessageBodyMember]
public string InputMessage { get; set; }
}
// MyResponse.cs
using CoreWCF;
[MessageContract]
public class MyResponse
{
[MessageBodyMember]
public string OutputMessage { get; set; }
}
And now the XML output is as it should be, without the extra layer.
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<MyResponse xmlns="http://tempuri.org/">
<OutputMessage>Hello world</OutputMessage>
</MyResponse>
</s:Body>
</s:Envelope>
Switching to CoreWCF fixed our nested XML problem in our SOAP service in ASP.NET Core 6.0. If you’re facing similar issues, giving CoreWCF a try might do the trick.