I'm not really proficient in soap calls.
I should make the following soap call.
I suffered with it for several days, but it doesn't work.
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:v1="http://eeszt.gov.hu/ns/helloworld/ws/HelloWorldService/v1">
<soapenv:Header>
<wsse:Security soapenv:mustUnderstand="1" xmlns:wsse="http://docs.oasisopen.org/wss/2004/01/oasis- 200401-wss-wssecurity-secext-1.0.xsd"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurityutility-1.0.xsd">
<wsu:Timestamp wsu:Id="TS-B05DFFAAB2CD6C6C9E14363584263357">
<wsu:Created>2015-07-08T12:27:06.335Z</wsu:Created>
<wsu:Expires>2015-07-08T12:32:06.335Z</wsu:Expires>
</wsu:Timestamp>
<saml:Assertion ID="id-" ...</saml:Assertion>
</wsse:Security>
</soapenv:Header>
<soapenv:Body>
<v1:helloWorldRequest>
...
</v1:helloWorldRequest>
</soapenv:Body>
</soapenv:Envelope
That's what I tried
Create custom binding and webservice
CustomBinding wsBinding = new CustomBinding();
string baseAddress = "https://dev-if.eeszt.gov.hu:443/TOR";
EndpointAddress wsEndPointAddress = new EndpointAddress(new Uri(baseAddress));
wsBinding = CreateBindingForTp();
TorWSClient twsClient = new TorWSClient(wsBinding, wsEndPointAddress);
X509Certificate2 x509 = new X509Certificate2(#eesztCert.certFileName, #eesztCert.certPassword, X509KeyStorageFlags.MachineKeySet);
byte[] rawData = ReadFile(#eesztCert.certFileName);
x509.Import(rawData, #eesztCert.certPassword, X509KeyStorageFlags.MachineKeySet);
twsClient.ClientCredentials.ClientCertificate.Certificate = x509;
twsClient.Open();
Add security header and call webservice
SoapSecurityHeader soapSecurityHeader = new SoapSecurityHeader(Saml.samlTicket);
using (OperationContextScope scope = new OperationContextScope((IContextChannel)twsClient.InnerChannel))
{
OperationContext.Current.OutgoingMessageHeaders.Add(soapSecurityHeader);
}
try
{
gtrspt = twsClient.getTorzs(gtrt);
}
catch (Exception ex)
{
MessageBoxEx.Show(ex.Message, "Error !", MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Information);
}
Create security header
public class SoapSecurityHeader : MessageHeader
{
private readonly string _samlticket;
private readonly DateTime _createdDate;
public SoapSecurityHeader(string samlTicket)
{
_samlticket = samlTicket;
_createdDate = DateTime.Now;
}
public string Id { get; set; }
public override string Name
{
get { return "Security "; }
}
public override string Namespace
{
get { return "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"; }
}
protected override void OnWriteStartHeader(XmlDictionaryWriter writer, MessageVersion messageVersion)
{
writer.WriteStartElement("wsse", Name, Namespace);
writer.WriteXmlnsAttribute("wsu", "wsu http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");
}
protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion)
{
writer.WriteStartElement("wsu", "Timestamp", null);
writer.WriteAttributeString("wsu", "Id", null, "TimeId1");
writer.WriteElementString("wsu", "Created", null, _createdDate.ToUniversalTime().ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff'Z'"));
writer.WriteElementString("wsu", "Expires", null, _createdDate.AddSeconds(300).ToUniversalTime().ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff'Z'"));
writer.WriteEndElement();
string sml = Saml.samlTicket;
writer.WriteRaw("<saml:Assertion ID=" + #"""");
writer.WriteRaw(sml + #"""");
writer.WriteRaw("</saml:Assertion>");
}
}
}
Binding
public CustomBinding CreateBindingForTp()
{
CustomBinding customBinding = new CustomBinding();
TransportSecurityBindingElement security = new TransportSecurityBindingElement()
{
IncludeTimestamp = true,
MessageSecurityVersion = MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10
};
TextMessageEncodingBindingElement encoding = new TextMessageEncodingBindingElement(MessageVersion.Soap11, Encoding.UTF8);
HttpsTransportBindingElement transport = new HttpsTransportBindingElement() { TransferMode = TransferMode.Buffered, RequireClientCertificate = true, MaxReceivedMessageSize = Int32.MaxValue };
customBinding.Elements.Clear();
customBinding.Elements.Add(security);
customBinding.Elements.Add(encoding);
customBinding.Elements.Add(transport);
return customBinding;
}
I generated the proxy class from wsdl. Only one wsse header should be added.
The wsse header is not included in the webservice call.
I want a simpler solution.
Sorry for my bad English.
Thanks for the help.
Related
well I am trying to develop a soap client, it wanted its custom soapheader(i.e.usercred) to serialized, but after doing so I get this as error
System.Runtime.Serialization.InvalidDataContractException: 'Type 'ConsoleApp1.Program+usercred' cannot inherit from a type that is not marked with DataContractAttribute or SerializableAttribute. Consider marking the base type System.Web.Services.Protocols.SoapHeader with DataContractAttribute or SerializableAttribute, or removing them from the derived type.'
it kinda wants soapheader to be also serialized plz help
There are several ways to add custom soup header in your soup request.
For example you can create soup request using HTTPRequest where you can build soup envelope as you want. Client to send SOAP request and receive response
public override string Process(string UserName,string Password)
{
string uri = "https://serviceURL";
HttpWebRequest req = (HttpWebRequest)WebRequest.CreateDefault(new Uri(uri));
req.ContentType = "application/soap+xml; charset=utf-8";
req.Method = "POST";
string soapRequest = BuildSoapRequest(UserName,Password);
StreamWriter stm = new StreamWriter(req.GetRequestStream(), Encoding.UTF8);
stm.Write(soapRequest);
stm.Close();
try
{
HttpWebResponse wr = (HttpWebResponse)req.GetResponse();
StreamReader srd = new StreamReader(wr.GetResponseStream());
string response = srd.ReadToEnd();
return ExtractResponse(response);
}
catch (WebException e)
{
string error = "";
HttpWebResponse errRsp = (HttpWebResponse)e.Response;
if (errRsp != null)
{
using (StreamReader rdr = new StreamReader(errRsp.GetResponseStream()))
{
string line;
while ((line = rdr.ReadLine()) != null)
{
error += line;
}
}
}
throw new Exception(e.Message + "<br/> " + error);
}
catch (Exception e)
{
throw e;
}
}
private string BuildSoapRequest(string UserName,string Password)
{
StringBuilder soapRequest = new StringBuilder();
soapRequest.Append("<soap:Envelope xmlns:cor=\"http://www.caqh.org/SOAP/WSDL/CORERule2.2.0.xsd\" xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\" xmlns:tem=\"http://tempuri.org/\">");
soapRequest.Append("<soap:Header>");
soapRequest.Append("<wsse:Security xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\" xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\">");
soapRequest.Append("<wsse:UsernameToken>");
soapRequest.Append("<wsse:Username>" + UserName + "</wsse:Username>");
soapRequest.Append("<wsse:Password>" + Password + "</wsse:Password>");
soapRequest.Append("</wsse:UsernameToken>");
soapRequest.Append("</wsse:Security>");
soapRequest.Append("</soap:Header>");
soapRequest.Append("<soap:Body>");
soapRequest.Append("</soap:Body>");
soapRequest.Append("</soap:Envelope>");
return soapRequest.ToString();
}
private static string ExtractResponse(string soap)
{
}
If you are consuming WCF service then you can add custom behavior in your request.
Custom Endpoint Behavior not being used in WCF Client with Service Reference
public class CustomClientBehavior : IEndpointBehavior
{
string _username;
string _password;
public CustomClientBehavior(string username, string password)
{
_username = username;
_password = password;
}
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
CustomInspector inspector = new CustomInspector(_username, _password);
clientRuntime.MessageInspectors.Add(inspector);
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
}
public void Validate(ServiceEndpoint endpoint)
{
}
}
public class CustomClientBehaviorExtensionElement : BehaviorExtensionElement
{
string _username;
string _password;
public CustomClientBehaviorExtensionElement(string username, string password)
{
_username = username;
_password = password;
}
public override Type BehaviorType
{
get { return typeof(CustomClientBehavior); }
}
protected override object CreateBehavior()
{
return new CustomClientBehavior(_username, _password);
}
}
public class CustomInspector : IClientMessageInspector
{
string _username;
string _password;
public CustomInspector(string username, string password)
{
_username = username;
_password = password;
}
public void AfterReceiveReply(ref Message reply, object correlationState)
{
return;
}
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
request.Headers.Clear();
string headerText = "<wsse:UsernameToken xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\">" +
"<wsse:Username>{0}</wsse:Username>" +
"<wsse:Password Type=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText\">" +
"{1}</wsse:Password>" +
"</wsse:UsernameToken>";
headerText = string.Format(headerText, _username, _password);
XmlDocument MyDoc = new XmlDocument();
MyDoc.LoadXml(headerText);
XmlElement myElement = MyDoc.DocumentElement;
System.ServiceModel.Channels.MessageHeader myHeader = MessageHeader.CreateHeader("Security", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", myElement, false);
request.Headers.Add(myHeader);
return Convert.DBNull;
}
}
Test Client should be like
TestService.Client objClient = new TestService.Client();
objClient.Endpoint.Behaviors.Add(new CustomClientBehavior(UserName, Password));
You can also try WebService Headers Authentication
I'm trying to make a call to a webservice and want to manually add the ws-security headers into the request because .net core 2.2 currently does not support ws-security.
I have created my custom security header class:
public class SoapSecurityHeader : MessageHeader
{
private readonly string _password, _username;
public SoapSecurityHeader(string id, string username, string password)
{
_password = password;
_username = username;
}
public override bool MustUnderstand => true;
public override string Name
{
get { return "Security"; }
}
public override string Namespace
{
get { return "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"; }
}
protected override void OnWriteStartHeader(XmlDictionaryWriter writer, MessageVersion messageVersion)
{
writer.WriteStartElement("wsse", Name, Namespace);
writer.WriteAttributeString("s", "mustUnderstand", "http://schemas.xmlsoap.org/soap/envelope/", "1");
writer.WriteXmlnsAttribute("wsse", Namespace);
}
protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion)
{
writer.WriteStartElement("wsse", "UsernameToken", Namespace);
writer.WriteAttributeString("wsu", "Id", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", "UsernameToken-32");
// Username
writer.WriteStartElement("wsse", "Username", Namespace);
writer.WriteValue(_username);
writer.WriteEndElement();
// Password
writer.WriteStartElement("wsse", "Password", Namespace);
writer.WriteAttributeString("Type", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText");
writer.WriteValue(_password);
writer.WriteEndElement();
writer.WriteEndElement();
}
}
And this is my method calling the SOAP service:
public ActionResult<Ted_Result> Get(DateTime dateFrom, DateTime dateTo, int? pageFrom, int? pageTo)
{
BasicHttpBinding basicHttpBinding = new BasicHttpBinding(BasicHttpSecurityMode.Transport);
basicHttpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
EndpointAddress endpointAddress = new EndpointAddress(new Uri("https://localhost/SomeService.svc"));
ChannelFactory<IConnectPublicService> factory = new ChannelFactory<IConnectPublicService>(basicHttpBinding, endpointAddress);
GetContractNoticesResponseMessage result = null;
// Bypass SSL/TLS secure channel validation
#if DEBUG
factory.Credentials.ServiceCertificate.SslCertificateAuthentication = new X509ServiceCertificateAuthentication
{
CertificateValidationMode = X509CertificateValidationMode.None,
RevocationMode = X509RevocationMode.NoCheck
};
#endif
// Debugging inspector
factory.Endpoint.EndpointBehaviors.Add(new InspectorBehavior());
IConnectPublicService serviceProxy = factory.CreateChannel();
((ICommunicationObject)serviceProxy).Open();
var opContext = new OperationContext((IClientChannel)serviceProxy);
var soapSecurityHeader = new SoapSecurityHeader("UsernameToken-32", "sampleUsername", "samplePassword123");
// Adding the security header
opContext.OutgoingMessageHeaders.Add(soapSecurityHeader);
var prevOpContext = OperationContext.Current; // Optional if there's no way this might already be set
OperationContext.Current = opContext;
var info = new ExternalIntegrationRequestMessageInfo
{
UserCode = "1000249",
CompanyCode = "200000040"
};
var request = new GetContractNoticesRequestMessage
{
Info = info,
DateFrom = dateFrom,
DateTo = dateTo,
PageFrom = pageFrom,
PageTo = pageTo
};
result = serviceProxy.GetContractNoticesAsync(request).ConfigureAwait(false).GetAwaiter().GetResult();
return Ok(result);
}
If I put a breakpoint inside the inspector at BeforeSendRequest I can see that the security header is added to the request:
<wsse:Security s:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken wsu:Id="UsernameToken-32" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:Username>sampleUsername</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">samplePassword123</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
And putting a breakpoint inside the inspector at AfterReceiveReply, I get the CORRECT result, but I still get an exception.
The result:
<...>
<s:Header>
<...>
<o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<u:Timestamp u:Id="_0">
<u:Created>2019-01-11T19:42:53.606Z</u:Created>
<u:Expires>2019-01-11T19:47:53.606Z</u:Expires>
</u:Timestamp>
</o:Security>
</s:Header>
<s:Body>
<GetContractNoticesResponseMessage>
<ContractNotices>....</ContractNotices>
</GetContractNoticesResponseMessage>
</s:Body>
The exception:
An unhandled exception occurred while processing the request.
ProtocolException: The header 'Security' from the namespace 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd' was not understood by the recipient of this message, causing the message to not be processed. This error typically indicates that the sender of this message has enabled a communication protocol that the receiver cannot process. Please ensure that the configuration of the client's binding is consistent with the service's binding.
Why do I still get an exception after calling the webservice successfully?
For .net core 2.2 you need to pass Security header manually. You'll need to-do some workarounds - WCF isn't fully implemented yet in .Net Core (has been stated by project contributors). Assuming the requirements aren't too complex, you should be able to get something going without too much headache.
public class SecurityHeader : MessageHeader
{
public UsernameToken UsernameToken { get; set; }
public override string Name => "Security";
public override string Namespace => "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
public override bool MustUnderstand => true;
protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion)
{
XmlSerializer serializer = new XmlSerializer(typeof(UsernameToken));
serializer.Serialize(writer, this.UsernameToken);
}
}
[XmlRoot(Namespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd")]
public class UsernameToken
{
[XmlAttribute(Namespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd")]
public string Id { get; set; }
[XmlElement]
public string Username { get; set; }
}
Add below code in BeforeSendRequest method
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
var soapSecurityHeader = new SecurityHeader()
{
UsernameToken = new UsernameToken()
{
Username = "User Name"
}
};
request.Headers.Add(soapSecurityHeader);
}
I did some digging and in the AfterReceiveReply you could do this:
public void AfterReceiveReply(ref Message reply, object correlationState)
{
var security = reply.Headers.Where(w => w.Namespace == "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd").First();
reply.Headers.UnderstoodHeaders.Add(security);
}
I suppose that in this step you could also check the value of the timestamp, if DateTime.UtcNow is in range and act upon that...?
Hi guys i'm new to soap and we started working with some service that make post calls to my asmx with xml.
inside my project in asmx file i need to build the model that i receive from them. so i have the xml:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<Exit xmlns="http://tempuri.org/">
<UserName>daniel#xxx.com</UserName>
<Password>123456</Password>
<parkingLotId>21</parkingLotId>
<gateNumber>EX 41</gateNumber>
<ticketNumber>123123123123123123123</ticketNumber>
<plateNumber>12211221</plateNumber>
<paymentSum>10.0</paymentSum>
<ExitDateTime>2018-12-23T09:56:10</ExitDateTime>
<referenceId>987462187346238746263</referenceId>
</Exit>
</s:Body>
</s:Envelope>
when i paste this xml in visual studio Edit -> Special Pase -> Paste XML As Class it builds the model for me with xml attributes like:
[XmlRoot(ElementName = "Exit", Namespace = "http://tempuri.org/")]
public class Exit
{
[XmlElement(ElementName = "UserName", Namespace = "http://tempuri.org/")]
public string UserName { get; set; }
....
}
[XmlRoot(ElementName = "Body", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
public class Body
{
[XmlElement(ElementName = "Exit", Namespace = "http://tempuri.org/")]
public Exit Exit { get; set; }
}
[XmlRoot(ElementName = "Envelope", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
public class Envelope
{
[XmlElement(ElementName = "Body", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
public Body Body { get; set; }
[XmlAttribute(AttributeName = "s", Namespace = "http://www.w3.org/2000/xmlns/")]
public string S { get; set; }
}
but! i get error every time i do POST request with this data:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<soap:Fault>
<soap:Code>
<soap:Value>soap:Receiver</soap:Value>
</soap:Code>
<soap:Reason>
<soap:Text xml:lang="en">System.Web.Services.Protocols.SoapException: Server was unable to process request. ---> System.Xml.XmlException: Root element is missing.
at System.Xml.XmlTextReaderImpl.Throw(Exception e)
at System.Xml.XmlTextReaderImpl.ParseDocumentContent()
at System.Xml.XmlTextReaderImpl.Read()
at System.Web.Services.Protocols.SoapServerProtocol.SoapEnvelopeReader.Read()
at System.Xml.XmlReader.MoveToContent()
at System.Web.Services.Protocols.SoapServerProtocol.SoapEnvelopeReader.MoveToContent()
at System.Web.Services.Protocols.SoapServerProtocolHelper.GetRequestElement()
at System.Web.Services.Protocols.Soap12ServerProtocolHelper.RouteRequest()
at System.Web.Services.Protocols.SoapServerProtocol.RouteRequest(SoapServerMessage message)
at System.Web.Services.Protocols.SoapServerProtocol.Initialize()
at System.Web.Services.Protocols.ServerProtocolFactory.Create(Type type, HttpContext context, HttpRequest request, HttpResponse response, Boolean& abortProcessing)
--- End of inner exception stack trace ---</soap:Text>
</soap:Reason>
<soap:Detail />
</soap:Fault>
</soap:Body>
</soap:Envelope>
and this is my code:
[WebMethod]
public string Exit()
{
XmlDocument xmlSoapRequest = new XmlDocument();
using (Stream receiveStream = HttpContext.Current.Request.InputStream)
{
receiveStream.Position = 0;
using (StreamReader readStream = new StreamReader(receiveStream, Encoding.UTF8)) { xmlSoapRequest.Load(readStream); }
}
var password = xmlSoapRequest?.GetElementsByTagName("Password")?.Item(0)?.FirstChild?.Value;
var userName = xmlSoapRequest?.GetElementsByTagName("UserName")?.Item(0)?.FirstChild?.Value;
var parkingLotId = xmlSoapRequest?.GetElementsByTagName("parking_lot_Id")?.Item(0)?.FirstChild?.Value;
var gateNumber = xmlSoapRequest?.GetElementsByTagName("gateNumber")?.Item(0)?.FirstChild?.Value;
var plateNumber = xmlSoapRequest?.GetElementsByTagName("plateNumber")?.Item(0)?.FirstChild?.Value;
var paymentSum = xmlSoapRequest?.GetElementsByTagName("paymentSum")?.Item(0)?.FirstChild?.Value;
var exitDateTime = xmlSoapRequest?.GetElementsByTagName("ExitDateTime")?.Item(0)?.FirstChild?.Value;
var referenceId = xmlSoapRequest?.GetElementsByTagName("referenceId")?.Item(0)?.FirstChild?.Value;
var exitParking = new Exit
{
ExitDateTime = Convert.ToDateTime(exitDateTime),
gateNumber = gateNumber,
parkingLotId = Convert.ToByte(parkingLotId),
Password = Convert.ToUInt32(password),
paymentSum = Convert.ToDecimal(paymentSum),
plateNumber = Convert.ToUInt32(plateNumber),
referenceId = referenceId,
UserName = userName
};
JavaScriptSerializer jsonSerializer = new JavaScriptSerializer();
var jsonObject = jsonSerializer.Serialize(exitParking);
var content = new StringContent(jsonObject, Encoding.UTF8, "application/json");
HttpClient client = new HttpClient();
var result = client.PostAsync("http://merchant-api-eb-parking-prod.eu-west-1.elasticbeanstalk.com/v1/parkings/exit", content).Result;
Context.Response.Output.Write($"<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"><s:Body><ExitResponse xmlns=\"http://tempuri.org/\"><ExitResult xmlns:a=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:i=\"http://www.w3.org/2001/XMLSchema\"><a:Status>OK</a:Status></ExitResult></ExitResponse></s:Body></s:Envelope>");
Context.Response.ContentType = "text/xml";
Context.Response.End();
return string.Empty;
}
i can see the data i post in Global.asax in Request Object
i see the xml i post as string but after global asax it throws exception.
i have Root attribute but in exception it says: Root element is missing
Thank You!
Ok figured it out!
the reason for error was:
<Exit xmlns="http:--tempuri-org-">
the namespace (xmlns) have to be my website url on sever
http:--mysite-com-
instead of
http:--tempuri-org-
I'm quite new to MVC and Web API.
I'm trying to post a MailMessage(System.Net.Mail) object to the web api that I've created but the object is received as empty at API. I'm using ReshSharp to call the api below is my code:
MailMessage myMail = new System.Net.Mail.MailMessage("from#example.com", "to#example.com");
myMail.Subject = "Test message from client";
myMail.SubjectEncoding = System.Text.Encoding.UTF8;
myMail.Body = "<b>Test Mail</b><br>using <b>HTML from client</b>.";
myMail.BodyEncoding = System.Text.Encoding.UTF8;
myMail.IsBodyHtml = true;
RestClient client = new RestClient("http://localhost:53014/api/email");
var request = new RestRequest("SendMailMessage", Method.POST);
var json = request.JsonSerializer.Serialize(myMail);
request.AddParameter("application/json; charset=utf-8", json, ParameterType.RequestBody);
request.RequestFormat = DataFormat.Json;
var res = client.Execute(request);
This is my API method:
[HttpPost]
public void SendMailMessage([FromBody]MailMessage myEmail)
{
//Code to send email
}
This is what I receive at the API end:
I have also tried this way but same output:
request = new RestRequest("SendMailMessage", Method.POST);
request.RequestFormat = DataFormat.Json;
request.AddBody(myMail);
res = client.Execute(request);
I have also tried the Newtonsoft.Json serializer to serialize object but no success
var json = JsonConvert.SerializeObject(myMail);
Can anyone suggest what am I missing here?
Trying to send a MailMessage is problematic.
You should create a custom object to hold the information you want sent to the web API...
public class Email {
public string Body { get; set; }
public bool IsBodyHtml { get; set; }
public string Subject { get; set; }
public string[] To { get; set; }
//...Any other properties you deem relevant
//eg: public string From { get; set; }
}
Keep it simple.
So now you would send the custom object to the web api
var myMail = new Email() {
To = new [] { "to#example.com" },
Subject = "Test message from client",
Body = "<b>Test Mail</b><br>using <b>HTML from client</b>.",
IsBodyHtml = true
};
var client = new RestClient("http://localhost:53014/api/email");
var request = new RestRequest("SendMailMessage", Method.POST);
var json = request.JsonSerializer.Serialize(myMail);
request.AddParameter("application/json; charset=utf-8", json, ParameterType.RequestBody);
request.RequestFormat = DataFormat.Json;
var res = client.Execute(request);
Then construct the mail message in the action using the properties provided to the action.
public class EmailController : ApiController {
[HttpPost]
public async Task<IHttpActionResult> SendMailMessage([FromBody]Email message) {
if (ModelState.IsValid) {
var myMail = new System.Net.Mail.MailMessage();
myMail.Subject = message.Subject;
myMail.SubjectEncoding = System.Text.Encoding.UTF8;
myMail.Body = message.Body;
myMail.BodyEncoding = System.Text.Encoding.UTF8;
myMail.IsBodyHtml = message.IsBodyHtml;
myMail.From = new MailAddress("from#example.com");
foreach (var to in message.To) {
myMail.To.Add(to);
}
//...Code to send email
}
return BadRequest(ModelState);
}
}
When I send a request from Android to ASP.NET method there is an error:
W/DefaultRequestDirector﹕ Authentication error: Unable to respond to any of these challenges: {}
W/MainActivity﹕ Error 401 for URL
I/jsonResultStr :﹕ {"Message":"There was an error processing the request.","StackTrace":"","ExceptionType":""}
This is the ASP.NET method prototype:
public string GetBuildingData(string roadId)
This is the Android sendToAsp method:
public void sendToAsp() {
HttpPost httpPost = new HttpPost("http://madenati.alameentech.com:8082/Coding/Services/BuildingsServices.asmx/GetBuildingData");
httpPost.setHeader("content-type", "application/json");
HttpClient httpClient = new DefaultHttpClient(getHttpParameterObj(4000,4000));
JSONObject data = new JSONObject();
try {
data.put("roadId", "1");
StringEntity entity = new StringEntity(data.toString(), HTTP.UTF_8);
httpPost.setEntity(entity);
HttpResponse response = httpClient.execute(httpPost);
BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), "UTF-8"));
String jsonResultStr = reader.readLine();
data = new JSONObject(jsonResultStr);
final int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
Log.w(getClass().getSimpleName(), "Error " + statusCode + " for URL " );
}
Log.i("jsonResultStr : ",jsonResultStr);
} catch(Exception e) {
Log.v("Exception","Exception sendToAsp");
}
}
This is getHttpParameterObj method:
private HttpParams getHttpParameterObj(int timeOutConnection,int timeOutSocket)
{
HttpParams httpParameters = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpParameters, timeOutConnection);
HttpConnectionParams.setSoTimeout(httpParameters, timeOutSocket);
return httpParameters;
}
and in Manifest.xml
<uses-permission android:name="android.permission.INTERNET" />
What could be the problem?
Use this class to do request:
package com.alameen.mat;
import android.app.Activity;
import android.os.AsyncTask;
import android.util.Log;
import org.ksoap2.SoapEnvelope;
import org.ksoap2.SoapFault;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpTransportSE;
public class WebService extends AsyncTask<String, String, String>
{
public String NameSpace = "";
public String MethodName = "";
SoapObject request;
SoapSerializationEnvelope envelope;
HttpTransportSE androidHttpTransport;
String URL="";
Activity context;
public WebService(Activity c, String nameSpace, String method, String url)
{
context=c;
NameSpace=nameSpace;
MethodName=method;
request = new SoapObject(NameSpace, MethodName);
envelope = new SoapSerializationEnvelope(SoapEnvelope.VER12);
envelope.setOutputSoapObject(request);
envelope.dotNet = true;
URL=url;
androidHttpTransport = new HttpTransportSE(URL,30000);
}
public void addProperty(String name,String val)
{
request.addProperty(name,val);
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
//Log.i("jsonArray from ASP.NET: ",result);
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(String... params) {
try
{
androidHttpTransport.call(params[0], envelope);
SoapObject result = (SoapObject)envelope.bodyIn;
String res = result.getProperty(0).toString();
//Log.d("result", res);
return res;
}
catch(Exception e)
{
SoapFault fault = (SoapFault)envelope.bodyIn;
Log.d("error", fault.getMessage()+"/"+fault.getCause());
e.printStackTrace();
}
return null;
}
void log(String l)
{
Log.d("status", l);
}
}
call like this:
public static String URL="http://... .asmx?WSDL";
WebService ws = new WebService(This, "http://tempuri.org/", "methodName", URL);
and import this library to your project:
https://www.dropbox.com/s/j5bi6yt8x5xpdbk/ksoap2-android-assembly-2.6.0-jar-with-dependencies.jar?dl=0