Ответ 1
Я далек от полномочий по этим вопросам, и хотя этот ответ ниже, возможно, не подходит для вашей проблемы, мой недавний опыт подключения к службе без прокси может предложить вам некоторое представление о вас или о следующем человеке с аналогичная проблема.
Начну с того, что вы сможете вручную загрузить запрос SOAP с помощью скрипача и посмотреть, сможете ли вы создать правильное сообщение и отправить его. Поскольку вы описываете инструменты автоматизации как ошибочные (или, возможно, проблема с конфигурацией, которую вы не получаете именно так). В любом случае, имея четкое представление о форме контракта и возможность провести надежный тест у скрипача, может проявляться ясность.
Вам необязательно полагаться на использование прокси. Вы можете создать свое собственное мыльное сообщение и отправить его одним из двух способов. Первый использует ChannelFactory.
- Создайте тело сообщения (если требуется, класс сообщений может работать без него)
- Создайте свое сообщение
- Отправьте свое сообщение через ChannelFactory
Для шага 1 вы можете создать свое сообщение, сделав простой POCO, чтобы отразить то, что ожидается в вашем контракте. Вы должны иметь возможность получить, что этот класс через WSDL.
Предположим, что сервис выглядит примерно так:
[ServiceContract(Namespace = "http://Foo.bar.car")]
public interface IPolicyService
{
[OperationContract]
PolicyResponse GetPolicyData(PolicyRequest request);
}
public class PolicyData : IPolicyService
{
public PolicyResponse GetPolicyData(PolicyRequest request)
{
var polNbr = request.REQ_POL_NBR;
return GetMyData(polNbr);
}
}
Вам понадобится класс примерно так:
[DataContract(Namespace = "http://Foo.bar.car")]
public class GetPolicyData
{
[DataMember]
public request request { get; set; }
}
[DataContract(Namespace = "http://schemas.datacontract.org/2004/07/Foo.bar.car.Model.Policy")]
public class request
{
///<summary>
/// Define request parameter for SOAP API to retrieve selective Policy level data
/// </summary>
[DataMember]
public string REQ_POL_NBR { get; set; }
}
а затем вы бы назвали это следующим образом:
private static Message SendMessage(string id)
{
var body = new GetPolicyData {request = new request{ REQ_POL_NBR = id }};
var message = Message.CreateMessage(MessageVersion.Soap11, "http://Foo.bar.car/IPolicyService/GetPolicyData", body);
// these headers would probably not be required, but added for completeness
message.Headers.Add(MessageHeader.CreateHeader("Accept-Header", string.Empty, "application/xml+"));
message.Headers.Add(MessageHeader.CreateHeader("Content-Type", string.Empty, "text/xml"));
message.Headers.Add(MessageHeader.CreateHeader("FromSender", string.Empty, "DispatchMessage"));
message.Headers.To = new System.Uri(@"http://localhost:5050/PolicyService.svc");
var binding = new BasicHttpBinding(BasicHttpSecurityMode.None)
{
MessageEncoding = WSMessageEncoding.Text,
MaxReceivedMessageSize = int.MaxValue,
SendTimeout = new TimeSpan(1, 0, 0),
ReaderQuotas = { MaxStringContentLength = int.MaxValue, MaxArrayLength = int.MaxValue, MaxDepth = int.MaxValue }
};
message.Properties.Add("Content-Type", "text/xml; charset=utf-8");
message.Properties.Remove("Accept-Encoding");
message.Properties.Add("Accept-Header", "application/xml+");
var cf = new ChannelFactory<IRequestChannel>(binding, new EndpointAddress(new Uri("http://localhost:5050/PolicyService.svc")));
cf.Open();
var channel = cf.CreateChannel();
channel.Open();
var result = channel.Request(message);
channel.Close();
cf.Close();
return result;
}
То, что вы получите назад, будет Message, которое вам нужно будет десериализовать, и есть несколько способов OOTB сделать это (Message.GetReaderAtBodyContents, Message.GetBody) в соответствии с ручной темой:
/// <summary>
/// Class MessageTransform.
/// </summary>
public static class MessageTransform
{
/// <summary>
/// Gets the envelope.
/// </summary>
/// <param name="message">The message.</param>
/// <returns>XDocument.</returns>
public static XDocument GetEnvelope(Message message)
{
using (var memoryStream = new MemoryStream())
{
var messageBuffer = message.CreateBufferedCopy(int.MaxValue);
var xPathNavigator = messageBuffer.CreateNavigator();
var xmlWriter = XmlWriter.Create(memoryStream);
xPathNavigator.WriteSubtree(xmlWriter);
xmlWriter.Flush();
xmlWriter.Close();
memoryStream.Position = 0;
var xdoc = XDocument.Load(XmlReader.Create(memoryStream));
return xdoc;
}
}
/// <summary>
/// Gets the header.
/// </summary>
/// <param name="message">The message.</param>
/// <returns>XNode.</returns>
public static XNode GetHeader(Message message)
{
var xdoc = GetEnvelope(message);
var strElms = xdoc.DescendantNodes();
var header = strElms.ElementAt(1);
return header;
}
/// <summary>
/// Gets the body.
/// </summary>
/// <param name="message">The message.</param>
/// <param name="localName">Name of the local.</param>
/// <param name="namespaceName">Name of the namespace.</param>
/// <returns>IEnumerable<XElement>.</returns>
public static IEnumerable<XElement> GetBody(Message message, string localName, string namespaceName)
{
var xdoc = GetEnvelope(message);
var elements = xdoc.Descendants(XName.Get(localName, namespaceName));
return elements;
}
}
ИЛИ вы могли бы создать свой конверт для мыла вручную и использовать WebClient:
using System.Net;
using System.Xml.Linq;
public static class ClientHelper
{
public static string Post(string targetUrl, string action, string method, string key, string value)
{
var request = BuildEnvelope(method, key, value);
using (var webClient = new WebClient())
{
webClient.Headers.Add("Accept-Header", "application/xml+");
webClient.Headers.Add("Content-Type", "text/xml; charset=utf-8");
webClient.Headers.Add("SOAPAction", action);
var result = webClient.UploadString(targetUrl, "POST", request);
return result;
}
}
public static string BuildEnvelope(string method, string key, string value)
{
XNamespace s = "http://schemas.xmlsoap.org/soap/envelope/";
XNamespace d = "d4p1";
XNamespace tempUri = "http://tempuri.org/";
XNamespace ns = "http://Foo.bar.car";
XNamespace requestUri = "http://schemas.datacontract.org/2004/07/Foo.bar.car.Model.Policy";
var xDoc = new XDocument(
new XElement(
s + "Envelope",
new XAttribute(XNamespace.Xmlns + "s", s),
new XElement(
s + "Body",
new XElement(
ns + method,
new XElement(requestUri + "request",
new XElement(tempUri + key, value))
)
)
)
);
// hack - finish XDoc construction later
return xDoc.ToString().Replace("request xmlns=", "request xmlns:d4p1=").Replace(key, "d4p1:" + key);
}
который вызывается с помощью:
return ClientHelper.Post("http://localhost:5050/PolicyService.svc", "http://Foo.bar.car/IPolicyService/GetPolicyData", "GetPolicyData", "REQ_POL_NBR", id);
Тестирование в Fiddler будет выглядеть примерно так:
Post action: http://localhost:5050/PolicyService.svc
Header:
User-Agent: Fiddler
SOAPAction: http://Foo.bar.car/IPolicyService/GetPolicyData
Content-type: text/xml
Host: localhost:5050
Content-Length: 381
Тело
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<GetPolicyData xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://Foo.bar.car">
<request xmlns:d4p1="http://schemas.datacontract.org/2004/07/Foo.bar.car.Model.Policy">
<d4p1:REQ_POL_NBR>1</d4p1:REQ_POL_NBR>
</request>
</GetPolicyData>
</s:Body>
</s:Envelope>
Опять же, этот ответ не пытается решить, как вызывать svcUtil по-разному, но чтобы не называть его вообще, поэтому я надеюсь, что боги редактирования не заставляют меня за это; -)
Мой код выше был вдохновлен лучшими разработчиками, чем я, но я надеюсь, что это поможет.