Первый контракт WCF для исходящих сообщений Salesforce - PullRequest
17 голосов
/ 07 февраля 2012

Я смотрю на реализацию приложения прослушивателя для Salesforce Outbound Messaging.

Обход через реализует его с помощью устаревшего веб-сервиса ASMX. Код генерируется с помощью wsdl.exe с ключом / serverInterface.

Вот wsdl исходящих сообщений Salesforce.

<?xml version="1.0" encoding="UTF-8"?>

<definitions targetNamespace="http://soap.sforce.com/2005/09/outbound"
   xmlns="http://schemas.xmlsoap.org/wsdl/"
   xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
   xmlns:tns="http://soap.sforce.com/2005/09/outbound"
   xmlns:xsd="http://www.w3.org/2001/XMLSchema"
   xmlns:ent="urn:enterprise.soap.sforce.com"
   xmlns:ens="urn:sobject.enterprise.soap.sforce.com">
<types>

    <schema elementFormDefault="qualified" xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:enterprise.soap.sforce.com">
        <!-- Our simple ID Type -->
        <simpleType name="ID">
            <restriction base="xsd:string">
                <length value="18"/>
                <pattern value='[a-zA-Z0-9]{18}'/>
            </restriction>
        </simpleType>
    </schema>

    <schema elementFormDefault="qualified" xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:sobject.enterprise.soap.sforce.com">
        <import namespace="urn:enterprise.soap.sforce.com" />
        <!-- Base sObject (abstract) -->
        <complexType name="sObject">
            <sequence>
                <element name="fieldsToNull" type="xsd:string" nillable="true" minOccurs="0" maxOccurs="unbounded"/>
                <element name="Id" type="ent:ID" nillable="true" />
            </sequence>
        </complexType>

        <complexType name="AggregateResult">
            <complexContent>
                <extension base="ens:sObject">
                    <sequence>
                        <any namespace="##targetNamespace" minOccurs="0" maxOccurs="unbounded" processContents="lax"/>
                    </sequence>
                </extension>
            </complexContent>
        </complexType>

        <complexType name="Contact">
            <complexContent>
                <extension base="ens:sObject">
                    <sequence>
                    <element name="Email" nillable="true" minOccurs="0" type="xsd:string"/>
                    <element name="FirstName" nillable="true" minOccurs="0" type="xsd:string"/>
                    <element name="LastName" nillable="true" minOccurs="0" type="xsd:string"/>
                    </sequence>
                </extension>
            </complexContent>
        </complexType>
    </schema>

    <schema elementFormDefault="qualified" xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://soap.sforce.com/2005/09/outbound">
        <import namespace="urn:enterprise.soap.sforce.com" />
        <import namespace="urn:sobject.enterprise.soap.sforce.com" />

        <element name="notifications">
            <complexType> 
                <sequence> 
                    <element name="OrganizationId" type="ent:ID" />
                    <element name="ActionId" type="ent:ID" />
                    <element name="SessionId" type="xsd:string" nillable="true" />
                    <element name="EnterpriseUrl" type="xsd:string" />
                    <element name="PartnerUrl" type="xsd:string" />
                    <element name="Notification" maxOccurs="100" type="tns:ContactNotification" />
                </sequence> 
            </complexType> 
        </element>

        <complexType name="ContactNotification">
            <sequence>
                <element name="Id" type="ent:ID" />
                <element name="sObject" type="ens:Contact" />
            </sequence>
        </complexType>

        <element name="notificationsResponse">
            <complexType>
                <sequence>
                    <element name="Ack" type="xsd:boolean" />
                </sequence>
            </complexType>
        </element>
    </schema>
</types>


<!-- Method Messages -->   
<message name="notificationsRequest">
    <part element="tns:notifications" name="request"/>
</message>
<message name="notificationsResponse">
    <part element="tns:notificationsResponse" name="response"/>
</message>

<!-- PortType -->
<portType name="NotificationPort">
    <operation name="notifications">
        <documentation>Process a number of notifications.</documentation>
        <input  message="tns:notificationsRequest"/>
        <output message="tns:notificationsResponse"/>
    </operation>
</portType>

<!-- Binding 
     You need to write a service that implements this binding to receive the notifications
 -->
<binding name="NotificationBinding" type="tns:NotificationPort">
    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>

    <operation name="notifications">
        <soap:operation soapAction=""/>
        <input>
            <soap:body use="literal"/>
        </input>
        <output> 
            <soap:body use="literal"/>
        </output>
    </operation>
</binding>

<!-- Service Endpoint -->
<service name="NotificationService">
    <documentation>Notification Service Implementation</documentation>
    <port binding="tns:NotificationBinding" name="Notification">
        <soap:address location="http://www.myserver.com/salesforceoutboundprototype/notificationport.svc"/>
    </port>
</service>    
</definitions>

tldr: мне нужно реализовать NotificationBinding, чтобы Salesforce мог вызывать мой веб-сервис, когда в их системе происходит событие.

С тех пор я понял, что svcutil изначально не поддерживает разработку Contract-First.

Согласно SOA первого контракта с WCF Я использовал WSCF.Blue для создания заглушек на стороне сервера из Salesforce wsdl. Хотя код, компилируемый wsdl, сгенерированный моим сервисом, не имеет требуемой операции уведомлений

Интересно, что я не так делаю?


Так что мне удалось быстро реализовать Salesforce wsdl с использованием wsdl.exe и / serverInterface, и кажется, что wsdl, сгенерированный приложением на основе asmx, сильно отличается от приложения на основе wcf.

Это интерфейс, созданный wsdl.exe с / serverInterface

/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "4.0.30319.1")]
[System.Web.Services.WebServiceBindingAttribute(Name="NotificationBinding", Namespace="http://soap.sforce.com/2005/09/outbound")]
[System.Xml.Serialization.XmlIncludeAttribute(typeof(sObject))]
public interface INotificationBinding {

    /// <remarks/>
    [System.Web.Services.WebMethodAttribute()]
    [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)]
    [return: System.Xml.Serialization.XmlElementAttribute("notificationsResponse", Namespace="http://soap.sforce.com/2005/09/outbound")]
    notificationsResponse notifications([System.Xml.Serialization.XmlElementAttribute("notifications", Namespace="http://soap.sforce.com/2005/09/outbound")] notifications notifications1);
}

Это интерфейс, созданный WSCF.Blue

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(Namespace="http://soap.sforce.com/2005/09/outbound", ConfigurationName="INotificationPort")]
public interface INotificationPort
{

    // CODEGEN: Generating message contract since the operation notifications is neither RPC nor document wrapped.
    [System.ServiceModel.OperationContractAttribute(Action="", ReplyAction="*")]
    [System.ServiceModel.XmlSerializerFormatAttribute(SupportFaults=true)]
    [System.ServiceModel.ServiceKnownTypeAttribute(typeof(sObject))]
    notificationsResponse1 notifications(notificationsRequest request);
}

Они кажутся довольно похожими, поэтому я не знаю, почему wsdl, сгенерированный этим приложением, будет таким разным? Стоит ли добавлять wsdls (не хочу ставить вопрос дольше, чем он есть)?

Ответы [ 5 ]

5 голосов
/ 16 февраля 2012

Возможно, вам не понравится то, что я предлагаю, но я верю, что это действительно будет лучшим вариантом для вас. Используйте ASMX. У меня три слушателя OM, и все они отлично работают под 4.0

Я не знаю, кто распространяет эти неправильные сведения о некоторых технологиях .NET2.0, но многие из них наверняка не устарели только потому, что сообщество разработчиков поражено новизной фетиша; ASMX является одним из них (как и Linq2SQL и т. Д.). Проще говоря, WCF еще не завершен, он не полностью совместим с WS и вызывает большие затруднения в связи с интеграцией salesforce (наиболее болезненным является то, что WCF не поддерживает мыльные заголовки, где salesforce хранит информацию о сеансе).

Подробнее о том, почему asmx НЕ устарел, см. Здесь: .NET 4.0 все еще поддерживает asmx

1 голос
/ 15 февраля 2012

Используйте svcutil для создания клиентского прокси и просто удалите реализацию клиентского прокси и сохраните контракты на обслуживание / данные.Контракт на обслуживание является симметричным с точки зрения клиента / сервера.Я работал над существенными проектами, основанными на контракте, и нашел, что это совершенно адекватно.

Просто убедитесь, что у вас есть все внешние WSDL, доступные для svcutil для разрешения.Я вижу несколько операторов импорта в вашем тексте WSDL выше.

Кстати, WSCF.Blue, к сожалению, не совсем подходит, поскольку он не обновлялся в течение нескольких месяцев и вряд ли будет таковым в будущем.К сожалению, основной разработчик погиб в автокатастрофе в прошлом году (да, действительно.)

0 голосов
/ 09 марта 2014

Я нашел простой способ создания интерфейсов WCF из Salesforce WSDL с использованием встроенных инструментов Visual Studio.Я загрузил WSDL из Salesforce и сохранил его на своем рабочем столе.В Visual Studio перейдите в меню добавления справочника услуг в одном из ваших проектов (не важно, где, вы собираетесь удалить это).В качестве URL-адреса введите путь к WSDL, который вы скачали локально (т. Е. C: \ Users \ yourusername \ Desktop \ messages.wsdl)

Это должно привести к загрузке данных для службы.Нажмите кнопку ОК, чтобы создать ссылку, и теперь в папке ссылок на услуги дважды щелкните ссылку, которую вы только что создали.Это должно показать вам браузер объектов с выделенным пространством имен ссылки на службу, которую вы только что создали.Дважды щелкните любой из классов в этом пространстве имен, и он откроет связанный файл reference.cs, сгенерированный Visual Studio.

Скопируйте весь контент в объявлении пространства имен в файл по вашему выбору с любымпространство имен вы решаете.Вы также можете переименовать этот интерфейс, если планируете обрабатывать более одного исходящего сообщения (по умолчанию должен быть NotificationPort).Интерфейс будет иметь ссылки на пространство имен, с которым вы его построили, но вы можете удалить все пространство имен в файле, поскольку все классы, на которые он ссылается, находятся в одном файле.

Создайте новый класс обслуживания WCF,Удалите интерфейс, который автоматически создается с помощью файла svc, и измените имя интерфейса на имя, которое вы только что скопировали в новый файл.

По умолчанию Visual Studio создала некоторый асинхронный метод, который выдавал ошибки, когда япытался это реализовать.Я просто удалил его из интерфейса и использовал стандартный метод уведомления.

Я сделал это в VS2013, но так же должно быть и в 2010, и в 2012 году.Убедитесь, что вы используете «Добавить ссылку на сервис», а не «Добавить веб-ссылку».Не забудьте удалить созданную ссылку, так как вы не будете ее использовать.

0 голосов
/ 18 февраля 2013

Я пережил ту же боль, пытаясь заставить моего слушателя OBM работать с WCF.Первоначально я только установил OperationContract для метода уведомлений.После развертывания я вскоре понял, что необходимо будет создать Data Contract, что я и сделал, но из-за нехватки времени и из-за неуверенности в том, что это все, что мне нужно, я просто переключился на работающий веб-сервис asmx.

0 голосов
/ 13 февраля 2012

WSCF предоставляет инструмент для контракта с интеграцией VS.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...