Reputation: 60734
I'm trying to consume a SOAP web service from an ASP.NET Core Library project.
I have installed the Mictosoft WCF Web Service Reference Provider that has created the proxy classes for me, but I have a problem with the authentication.
My code currently looks like this:
var binding = new BasicHttpBinding(BasicHttpSecurityMode.TransportWithMessageCredential);
var address = new EndpointAddress(@"https://myserviceaddress.asmx");
var client = new TestApiClient(binding, address);
client.ClientCredentials.UserName.UserName = "testusername";
client.ClientCredentials.UserName.Password = "testpassword";
var result = await client.GetDataAsync(params);
I have tried some different approaches, but I either get Unauthorized, or variants of this: The value 'TransportWithMessageCredential' is not supported in this context for the binding security property 'securityMode'.
.
I think I'm also supposed to set some properties on binding.Security.Message
, but the only property that exist on binding.Security
is Transport
and Mode
.
Anyone know how to set this up correctly?
Are there any other better ways of consuming the SOAP service from ASP.NET Core? I would love a dynamic way that don't have to create the proxy classes, but I can live with the proxies if I have to, but I need to be able to authenticate with a user and password, and I have to use https.
Upvotes: 5
Views: 10105
Reputation: 9121
After struggling many days with the same issue, because .Net core has a very limited support till date of this answer, I managed to solve it by building the whole envelope myself and using SimpleSoapClient.
I will try to go through all needed steps, step by step with a simple example. because each step has its own issues that needs to be solved.
Let us assume that your model is a Cat.
public class Cat
{
public int Lives { get; set; }
}
Your entire envelop model will look like:
public class Envelope
{
public EnvelopeHeader Header { get; set; }
public EnvelopeBody Body { get; set; }
}
public class EnvelopeHeader
{
[XmlElementAttribute(Namespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd")]
public Security Security { get; set; }
}
[XmlTypeAttribute(AnonymousType = true, Namespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd")]
[XmlRootAttribute(Namespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", IsNullable = false)]
public class Security
{
public SecurityUsernameToken UsernameToken { get; set; }
}
[XmlTypeAttribute(AnonymousType = true, Namespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd")]
public class SecurityUsernameToken
{
public string Username { get; set; }
public SecurityUsernameTokenPassword Password { get; set; }
[XmlAttributeAttribute(Form = System.Xml.Schema.XmlSchemaForm.Qualified, Namespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd")]
public string Id { get; set; }
}
[XmlTypeAttribute(AnonymousType = true, Namespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd")]
public class SecurityUsernameTokenPassword
{
[XmlAttributeAttribute()]
public string Type { get; set; }
[XmlTextAttribute()]
public string Value { get; set; }
}
public class EnvelopeBody
{
public Cat Cat{ get; set; }
}
P.S: do not forget to include XML namespaces where needed in your body.
Next step is serializing your Envelop model into XML string.
string xml;
XmlWriterSettings settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
using (MemoryStream ms = new MemoryStream())
{
using (XmlWriter writer = XmlWriter.Create(ms, settings))
{
XmlSerializerNamespaces names = new XmlSerializerNamespaces();
names.Add("", "");//add your needed namespaces here
XmlSerializer cs = new XmlSerializer(typeof(Envelope));
var myEnv = new Envelope()
{
Header = new EnvelopeHeader()
{
Security = new Security()
{
UsernameToken = new SecurityUsernameToken()
{
Username = "",
Password = new SecurityUsernameTokenPassword()
{
Type = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText",//update type to match your case
Value = ""
}
}
}
},
Body = new EnvelopeBody()
{
Cat = new Cat() { Lives = 7 }
}
};
cs.Serialize(writer, myEnv, names);
ms.Flush();
ms.Seek(0, SeekOrigin.Begin);
StreamReader sr = new StreamReader(ms);
xml = sr.ReadToEnd();
}
}
Finally send your XML envelop using:
SoapEnvelope responseEnvelope = null;
using (var client = SoapClient.Prepare().WithHandler(new DelegatingSoapHandler()
{
OnHttpRequestAsyncAction = async (z, x, y) =>
{
x.Request.Content = new StringContent(xml , Encoding.UTF8, "text/xml");
}
}))
{
responseEnvelope = client.SendAsync("url", "action",SoapEnvelope.Prepare()).Result;
}
Please note that you need to update many options according to your case. My case was password of type "PasswordText" in the WSSE Security Header with WCF.
Upvotes: 5
Reputation: 46641
Message security (TransportWithMessageCredential
on BasicHttpBinding
) is not yet supported in WCF on .NET Core 2.0.
Reference:
Upvotes: 3
Reputation: 60
Have you tried enabling SSL on IIS? Enabling SSL will make your service listen on both HTTP & HTTPS. your client needs to purchase SSL cert. for this
Upvotes: 0