5

尝试通过 BulkRequestTransmitter Web 服务提交时收到以下错误。就这条消息而言,Composition Guide 的帮助不大,当我将我的 SOAP XML 与 Composition Guide 中的 SOAP 进行比较时,它们似乎是相得益彰的。我希望另一双眼睛能够看到问题所在。

消息格式不正确和/或无法解释。请查看位于https://www.irs.gov/for-Tax-Pros/Software-Developers/Information-Returns/Affordable-Care-Act-Information的 AIR 提交组成和参考指南第 3 节中概述的 XML 标准-Return-AIR-Program,更正任何问题,然后重试。

我试过的:

  • 尝试在 SOAP 信封中提交带有(和不带有)空格的内容。
  • 尝试使用 XML 格式的表单数据 XML 提交。
  • 尝试使用base64string格式提交的表单数据(与本次提交一样)。
  • ds为 Signature 元素添加了前缀。使用此 SO 帖子将前缀添加到 Signature 元素。
  • 根据更新的合成指南 (v4.2) 添加了“Pretty Print”格式的表单数据。
  • 复制了撰写指南第10.3节中概述MIME的请求的格式。BulkTransmitterService
  • 创建了两个解决方案: 1.)手动创建 SOAP 请求所需的 XML 并通过HttpWebRequest对象发送;WSDL2.) 通过导入的项目发送提交请求Service Reference,使用自定义编码器GZip and Mtom Encoding并手动创建 SOAP 状态请求所需的 XML(通过发送HttpWebRequest)。

更新 #1
根据一些新增内容更新了请求。

  • ds为 Signature 元素添加了前缀。
  • 根据更新的合成指南(v4.2:第 5.4.2 节)添加了“Pretty Print”格式的表单数据。

更新 #2
我开始SOAP在 Visual Studio 的新实例中手动创建 .xml 文件,并根据需要导入架构引用。我在任何类型的应用程序创建之外执行此操作

在这样做的过程中,我能够在SOAP我通过我的应用程序创建的程序中找到一些额外的错误(感谢您的智能感知!)。我发现的错误在 Manifest XML 中,因为它们不符合 IRS 模式。

我将在接下来的 24 小时内调查这些内容并进行相应更新。

  • urn:MailingAddressGrp应该有一个urn:USAddressGrp或的孩子urn:ForeignAddressGrp。然后那个孩子应该包含正确的地址元素。我的代码目前缺少urn:MailingAddressGrp.
  • urn1:DocumentSystemFileNmof 的值Form1094C_Request_[TCC]_yyyyMMddThhmmssfffZ.xml不正确。我还不完全确定它应该是什么。
  • 该元素存在与我所拥有urn1:BulkExchangeFile的元素相关的问题。xop:Include架构需要 base64Binary 类型。

更新 #2.5

  • 更新了我的 XML 生成过程以包含该USAddressGrp元素。
  • 发现我在几毫秒内多了一个字符(四个而不是三个)。一旦我更正了这一点,并从文件名的开头删除字符串“Form”, 的值urn1:DocumentSystemFileNm就能够成功地验证架构。

更新#3

  • 根据我所做的更新更新了完整请求。在这一点上,我无法推断出我的请求有什么问题。如果有人看到任何刺眼的东西,请帮忙!

更新#4

  • 根据所做的其他更新更新了完整请求。ds根据另一个 SO 用户的反馈,从签名中删除了前缀。该用户已经使这些请求生效,而无需在ds事后将前缀附加到签名并重新计算签名。

    SO 用户还确认他的请求正在处理一个 <inc:Include>被设置为该元素的子元素的 <BulkExchangeFile>元素。

  • 根据合成指南第 10.3 节中的示例,确认MIME标题是正确的。

更新#5

  • 我目前有两种解决方案:一种是手动发送,创建 SOAP 请求所需的 XML 并通过发送HttpWebRequest;一种是使用WSDL Service Reference提交请求,使用下面概述的自定义编码器,并手动创建状态的 SOAP 请求所需的 XML。

    截至本次更新,解决方案 1 在发出提交请求时给我上面的错误,在发出状态请求时给我下面的错误。但是,在使用解决方案 2 时,两个请求(提交和状态)都会给我以下错误。

    我正在调查可能的证书问题,看看他们是否在这些解决方案中取得了任何进展。

更新 #6

我遇到了许多问题,导致我被耽搁了。我不会详细说明细节,但缺点是我们没有在 IRS 系统中注册安全证书,也没有正确安装证书,以便我可以通过X509Store. 最后,这些事情都完成了,我能够测试从服务器向 IRS 提交数据(与我的本地机器相比,它没有正确的证书)。不幸的是,我仍然收到下面详述的 WS-Security 错误。我已经用我当前发送的内容更新了完整请求。

消息发生错误:消息中的 WS 安全标头无效。请查看位于https://www.irs.gov/for-Tax-Pros/Software-Developers/Information-Returns/Affordable-Care-Act-Information的 AIR 提交组成和参考指南第 5 节中概述的传输说明-Return-AIR-Program,更正任何问题,然后重试。


MIME 标头中的所有换行符都是原样的,我相信换行符是预期的。 FormData 附件是作为 Pretty Print 发送的,而 SOAP Envelope 不是;这篇文章中的 SOAP 信封经过格式化以提高可读性。

更新#7:

感谢用户:jstill 和fatherOfWine 以及他们在下面发布的内容,并感谢 Bon 对这个项目的早期帮助。我已经打破了一堵墙让提交工作。它现在正在工作。状态请求也有效。但是,我需要弄清楚如何处理它以便从中提取状态和附件(错误数据文件)。

完整请求:

Content-Encoding: gzip
Accept-Encoding: gzip, deflate
Content-Type: multipart/related; type="application/xop+xml"; start="<rootpart>"; start-info="text/xml"; boundary="MIME_boundary"
SOAPAction: BulkRequestTransmitter
MIME-Version: 1.0
Host: la.www4.irs.gov

--MIME_Boundary
Content-Type: application/xop+xml; charset=UTF-8; type="text/xml"
Content-Transfer-Encoding: 8bit
Content-Id: <root_part>

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
    <s:Header>
        <Security xmlns:h="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
            <Signature Id="SIG-E77c57b78ebc54e989bfc9e43604a04a4" xmlns="http://www.w3.org/2000/09/xmldsig#">
                <SignedInfo>
                    <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#WithComments" />
                    <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
                    <Reference URI="#TS-Eb4799bee41bb4df0a72f52832d283ef7">
                        <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
                        <DigestValue>[TimestampDigestValue]</DigestValue>
                    </Reference>
                    <Reference URI="#id-E5f1ed32aab8f4578adeee5debd851a62">
                        <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
                        <DigestValue>[ACABusinessHeaderDigestValue]</DigestValue>
                    </Reference>
                    <Reference URI="#id-E4a71164001994d7f865fc7ddb8055350">
                        <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
                        <DigestValue>[ManifestDigestValue]</DigestValue>
                    </Reference>
                </SignedInfo>
                <SignatureValue>[SignatureValue]</SignatureValue>
                <KeyInfo Id="KI-E2309cb142e1a4076a2e71373e6e6b75f">
                    <SecurityTokenReference d6p1:Id="STR-E2751169ee468470290fe5e8bfb34589e" xmlns:d6p1="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
                        <KeyIdentifier EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3">[KeyIdentifier]</KeyIdentifier>
                    </SecurityTokenReference>
                </KeyInfo>
            </Signature>
            <a:Timestamp a:Id="TS-Eb4799bee41bb4df0a72f52832d283ef7" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:a="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
                <a:Created>2016-05-18T09:51:05.856Z</a:Created>
                <a:Expires>2016-05-18T10:01:05.856Z</a:Expires>
            </a:Timestamp>
        </Security>
        <ACATransmitterManifestReqDtl a:Id="id-E4a71164001994d7f865fc7ddb8055350" xmlns:h="urn:us:gov:treasury:irs:ext:aca:air:7.0" xmlns:a="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns="urn:us:gov:treasury:irs:ext:aca:air:7.0">
            <PaymentYr>2015</PaymentYr>
            <PriorYearDataInd>0</PriorYearDataInd>
            <EIN xmlns="urn:us:gov:treasury:irs:common">000000301</EIN>
            <TransmissionTypeCd>O</TransmissionTypeCd>
            <TestFileCd>T</TestFileCd>
            <OriginalReceiptId />
            <TransmitterNameGrp>
                <BusinessNameLine1Txt />
            </TransmitterNameGrp>
            <CompanyInformationGrp>
                <CompanyNm>Selitestthree</CompanyNm>
                <MailingAddressGrp>
                    <USAddressGrp>
                        <AddressLine1Txt>6689 Willow Court</AddressLine1Txt>
                        <CityNm xmlns="urn:us:gov:treasury:irs:common">Beverly Hills</CityNm>
                        <USStateCd>CA</USStateCd>
                        <USZIPCd xmlns="urn:us:gov:treasury:irs:common">90211</USZIPCd>
                    </USAddressGrp>
                </MailingAddressGrp>
                <ContactNameGrp>
                    <PersonFirstNm>Rose</PersonFirstNm>
                    <PersonLastNm>Lincoln</PersonLastNm>
                </ContactNameGrp>
                <ContactPhoneNum>5559876543</ContactPhoneNum>
            </CompanyInformationGrp>
            <VendorInformationGrp>
                <VendorCd>I</VendorCd>
                <ContactNameGrp>
                    <PersonFirstNm>ContactFirstName</PersonFirstNm>
                    <PersonLastNm>ContactLastName</PersonLastNm>
                </ContactNameGrp>
                <ContactPhoneNum>ContactPhoneNumber</ContactPhoneNum>
            </VendorInformationGrp>
            <TotalPayeeRecordCnt>3</TotalPayeeRecordCnt>
            <TotalPayerRecordCnt>1</TotalPayerRecordCnt>
            <SoftwareId>PPACA</SoftwareId>
            <FormTypeCd>1094/1095C</FormTypeCd>
            <BinaryFormatCd xmlns="urn:us:gov:treasury:irs:common">application/xml</BinaryFormatCd>
            <ChecksumAugmentationNum xmlns="urn:us:gov:treasury:irs:common">6b2512ce28f603f76261923d297738e5</ChecksumAugmentationNum>
            <AttachmentByteSizeNum xmlns="urn:us:gov:treasury:irs:common">14076</AttachmentByteSizeNum>
            <DocumentSystemFileNm>1094C_Request_[TCC]_20160518T215105716Z.xml</DocumentSystemFileNm>
        </ACATransmitterManifestReqDtl>
        <ACABusinessHeader a:Id="id-E5f1ed32aab8f4578adeee5debd851a62" xmlns:h="urn:us:gov:treasury:irs:msg:acabusinessheader" xmlns:a="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns="urn:us:gov:treasury:irs:msg:acabusinessheader">
            <UniqueTransmissionId xmlns="urn:us:gov:treasury:irs:ext:aca:air:7.0">51958882-c653-4eab-8dfb-287ecc555aaa:SYS12:[TCC]::T</UniqueTransmissionId>
            <Timestamp xmlns="urn:us:gov:treasury:irs:common">2016-05-18T14:51:05.8568594-07:00</Timestamp>
        </ACABusinessHeader>
    </s:Header>
    <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <ACABulkRequestTransmitter xmlns="urn:us:gov:treasury:irs:msg:irsacabulkrequesttransmitter" version="1.0">
            <BulkExchangeFile xmlns="urn:us:gov:treasury:irs:common">
                <inc:Include href="cid:1094C_Request_BB0S4_20160518T215105716Z.xml" xmlns:inc="http://www.w3.org/2004/08/xop/include" />
            </BulkExchangeFile>
        </ACABulkRequestTransmitter>
    </s:Body>
</s:Envelope>

--MIME_Boundary
Content-Type: text/xml; charset=us-ascii
Content-Transfer-Encoding: 7bit
Content-Id: <1094C_Request_[TCC]_20160518T215105716Z.xml>
Content-Disposition: attachment; name="1094C_Request_[TCC]_20160518T215105716Z.xml"

[PrettyPrintFormDataXml]
--MIME_boundary--
4

6 回答 6

4

不知道它是否能解决你的问题,但我还是试一试。有时帮助来自非常意想不到的来源:)

  1. 首先,时间戳字段格式错误:businessheader 中的字段根本不应包含毫秒。我知道这是事实。
  2. 在安全标头时间戳中,仅允许 3 位数字表示毫秒。
  3. 从 ACATransmitterManifestReqDtl 元素中删除像“OriginalReceiptId”这样的空元素:他们不喜欢那些。
  4. 我希望您为他们提供正确的软件 ID,因为您在有效负载中将其设为空,但我相信他们会很乐意拥有它,恕我直言。:)
  5. 我认为你在回复中得到的信息也与签名元素有关。我认为他们希望 Signature 元素具有一些前缀(我猜最好是“ds”)。但是在这里我不确定100%。

    你看,我在和你打同样的仗。而且我的消息安全时间戳有前缀“u”,他们不会抱怨。尽管他们从来都不喜欢 binarysecuritytoken。:) 我正在努力生成符合 IRS 喜好的签名。WCF 非常隐秘,不允许在肥皂信封上轻松更改前缀,也不允许为签名选择 CanonicalizationMethod 算法。

更新:能够成功地向服务发送请求。马上告诉你:前缀不重要。重要的是:Form1095BUpstreamDetail 中必须存在 CorrectedInd 标记,并且属性 recordType="String" lineNum="0" 也必须存在。

UPDATE2:我改变的另一件事是我将 ACABusinessHeader 放在 ManifestDtl 之前。这是我的设置:我使用 WCF 作为载体,使用 SignedXml 生成签名。此外,我正在使用自定义 gZip 编码器(出于显而易见的原因 0 和自定义 MtomEncoder 来读取来自服务的响应(是的,是的,它是 MTOMed :))你能相信那些口袋妖怪吗?!?!?)这还不是全部:它们将响应作为多部分文档发送只有 1 部分!:))我不得不调整我的编码器来处理这个问题。瞧,服务开始表现。希望它可能会有所帮助。

UPDATE3 首先确保附件文件中的数据与您用作豚鼠的测试场景相对应。我,可能,听起来像是一张破唱片,但这真的很重要。现在我将剪掉这些东西并展示我拥有的东西。这有点粗糙,但它确实有效。:)

1.这是配置文件部分:
1.1.确保 system.serviceModel 元素包含以下部分:

<extensions>
  <bindingElementExtensions>
    <add name="gzipMessageEncoding" type="<namespaceWhereEncoderLives>.GZipMessageEncodingElement, GZipEncoder, Version=4.0.0.0, Culture=neutral, PublicKeyToken=null" />
  </bindingElementExtensions>
</extensions>  

1.2. 确保绑定元素包含以下内容:

  <customBinding>
    <binding name="BulkRequestTransmitterBinding">
      <gzipMessageEncoding innerMessageEncoding="textMessageEncoding" />
      <httpsTransport />
    </binding>
  </customBinding>

1.3. 将客户端元素下 BulkRequestTransmitterPort 端点的绑定更改为“customBinding”(并将绑定名称也更改为自定义绑定的名称)并确保它包含以下部分:

    <identity>
      <dns value="domain from cert" />
    </identity>

客户端元素还应包含以下部分:

  <metadata>
    <policyImporters>
      <extension type="NamespaceToToTheLocationOf.GZipMessageEncodingBindingElementImporter, GZipMessageEncoder, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
    </policyImporters>
  </metadata>
  1. 您可以从以下链接获得 GZip 编码器: https : //msdn.microsoft.com/en-us/library/cc138373(v=vs.90).aspx 只需下载 WCF 示例并将整个 GZipMessageEncoder 项目平淡地移动到您的项目下。

  2. 从此链接获取 MTOMEncoder(为了清楚起见,我从 SwaEncoder 重命名): Soap-with-Attachments 将以下类移动到 GZipMessageEncoder 项目中:
    MimeContent、MimeParser、MimePart、MTOMEncoder

  3. 像这样修改 GZipMessageEncoder 类:
    4.1。在类的开头添加以下代码:

       //------------------- MTOM related stuff. Begin. ---------------------
        const string ATTCHMNT_PROP = "attachment_file_content";
        const string ATTCHMNT_CONTENT_ID = "Here goes content id";
    
        private string _ContentType;
        private string _MediaType;
    
        protected MimeContent _MyContent;
        protected MimePart _SoapMimeContent;
        protected MimePart _AttachmentMimeContent;
        protected GZipMessageEncoderFactory _Factory;
        protected MimeParser _MimeParser;
        private void SetupMTOM(GZipMessageEncoderFactory factory)
        {
            //
            _ContentType = "multipart/related";
            _MediaType = _ContentType;
    
            //
            // Create owned objects
            //
            _Factory = factory;
            _MimeParser = new MimeParser();
    
            //
            // Create object for the mime content message
            // 
            _SoapMimeContent = new MimePart()
            {
                ContentTypeStart = "application/xop+xml",
                ContentType = "text/xml",
                ContentId = "Here goes envelope MIME id from HTTP Content-Type header",   // TODO: make content id dynamic or configurable?
                CharSet = "UTF-8",                                  // TODO: make charset configurable?
                TransferEncoding = "8bit"                         // TODO: make transfer-encoding configurable?
            };
            _AttachmentMimeContent = new MimePart()
            {
                ContentType = "application/xml",                    // TODO: AttachmentMimeContent.ContentType configurable?
                ContentId = ATTCHMNT_CONTENT_ID,                    // TODO: AttachmentMimeContent.ContentId configurable/dynamic?
                TransferEncoding = "7bit"                         // TODO: AttachmentMimeContent.TransferEncoding dynamic/configurable?
            };
            _MyContent = new MimeContent()
            {
                Boundary = "here goes boundary id"  // TODO: MimeContent.Boundary configurable/dynamic?
           };
            _MyContent.Parts.Add(_SoapMimeContent);
            _MyContent.Parts.Add(_AttachmentMimeContent);
            _MyContent.SetAsStartPart(_SoapMimeContent);
        }
        //------------------- MTOM related stuff. End. ----------------------
    

4.2. 像这样修改方法 WriteMessage(Message message, int maxMessageSize, BufferManager bufferManager, int messageOffset):

public override ArraySegment<byte> WriteMessage(Message message, int maxMessageSize, BufferManager bufferManager, int messageOffset)
        {
            ArraySegment<byte> buffer = innerEncoder.WriteMessage(message, maxMessageSize, bufferManager, 0);
            var requestSOAPEnvelopeXml = System.Text.Encoding.UTF8.GetString(buffer.Array);

            //Here you create Security node and sign the request. For ex:
            requestSOAPEnvelopeXml = SigngEnvelope(requestSOAPEnvelopeXml);
            //Here you are getting 1094\1095 forms xml payload.
            string fileContent = GetAttachmentFileContent();

            //Here comes the MTOMing...
            _SoapMimeContent.Content = System.Text.Encoding.UTF8.GetBytes(requestSOAPEnvelopeXml);
            _AttachmentMimeContent.Content = System.Text.Encoding.UTF8.GetBytes(fileContent);

            _MyContent.Parts.Where(m=> m.ContentId!=null && m.ContentId.Equals(ATTCHMNT_CONTENT_ID)).Single().ContentDisposition = GetFileName(envelope);
            // Now create the message content for the stream
            byte[] MimeContentBytes = _MimeParser.SerializeMimeContent(_MyContent);
            int MimeContentLength = MimeContentBytes.Length;

            // Write the mime content into the section of the buffer passed into the method
            byte[] TargetBuffer = bufferManager.TakeBuffer(MimeContentLength + messageOffset);
            Array.Copy(MimeContentBytes, 0, TargetBuffer, messageOffset, MimeContentLength);

            // Return the segment of the buffer to the framework
            return CompressBuffer(new ArraySegment<byte>(TargetBuffer, messageOffset, MimeContentLength), bufferManager, messageOffset);                
        }

4.3. 覆盖更多这样的方法:

public override Message ReadMessage(ArraySegment<byte> buffer, BufferManager bufferManager, string contentType)
        {
            ArraySegment<byte> decompressedBuffer = DecompressBuffer(buffer, bufferManager);

            MtomEncoder mtomEncoder = new MtomEncoder(innerEncoder, _Factory);
            Message returnMessage = mtomEncoder.ReadMessage(buffer, bufferManager, contentType);
            returnMessage.Properties.Encoder = mtomEncoder;

            return returnMessage;
        }

        public override bool IsContentTypeSupported(string contentType)
        {
            return true;
        }

4.4. 确保 GZipMessage 构造函数如下所示:

        internal GZipMessageEncoder(MessageEncoder messageEncoder, GZipMessageEncoderFactory factory)
            : base()
        {
            if (messageEncoder == null)
                throw new ArgumentNullException("messageEncoder", "A valid message encoder must be passed to the GZipEncoder");
            innerEncoder = messageEncoder;

            SetupMTOM(factory);
        }

5. 确保 GZipMessageEncodingBindingElement 类具有以下方法:

    public override void ApplyConfiguration(BindingElement bindingElement)
    {
        GZipMessageEncodingBindingElement binding = (GZipMessageEncodingBindingElement)bindingElement;
        PropertyInformationCollection propertyInfo = this.ElementInformation.Properties;
        if (propertyInfo["innerMessageEncoding"].ValueOrigin != PropertyValueOrigin.Default)
        {
            switch (this.InnerMessageEncoding)
            {
                case "textMessageEncoding":
                    binding.InnerMessageEncodingBindingElement = 
                        new TextMessageEncodingBindingElement(MessageVersion.Soap11, Encoding.UTF8);
                    break;
                case "binaryMessageEncoding":
                    binding.InnerMessageEncodingBindingElement = new BinaryMessageEncodingBindingElement();
                    break;
            }
        }
    }
  1. 修改 MTOMEncoder 类。确保以下方法如下所示:

    public override Message ReadMessage(System.IO.Stream stream, int maxSizeOfHeaders, string contentType)
    {
        VerifyOperationContext();
    
        if (contentType.ToLower().StartsWith("multipart/related"))
        {
            byte[] ContentBytes = new byte[stream.Length];
            stream.Read(ContentBytes, 0, ContentBytes.Length);
            MimeContent Content = _MimeParser.DeserializeMimeContent(contentType, ContentBytes);
    
            if (Content.Parts.Count >= 1)
            {
                MemoryStream ms = new MemoryStream(Content.Parts[0].Content);
                //At least for now IRS is sending SOAP envelope as 1st part(and only part(sic!) of MULTIpart response) as xml. 
                Message Msg = ReadMessage(ms, int.MaxValue, "text/xml");//Content.Parts[0].ContentType);
    
                if( Content.Parts.Count>1 )
                    Msg.Properties.Add(ATTCHMNT_PROP, Content.Parts[1].Content);
    
                return Msg;
            }
            else
            {
                throw new ApplicationException("Invalid mime message sent! Soap with attachments makes sense, only, with at least 2 mime message content parts!");
            }
        }
        else if (contentType.ToLower().StartsWith("text/xml"))
        {
            XmlReader Reader = XmlReader.Create(stream);
            return Message.CreateMessage(Reader, maxSizeOfHeaders, MessageVersion);
        }
        else
        {
            throw new ApplicationException(
                string.Format(
                    "Invalid content type for reading message: {0}! Supported content types are multipart/related and text/xml!",
                    contentType));
        }
    }
    
  2. GZipMessageEncoderFactory 类构造函数应如下所示:

       public GZipMessageEncoderFactory(MessageEncoderFactory messageEncoderFactory)
    {
        if (messageEncoderFactory == null)
            throw new ArgumentNullException("messageEncoderFactory", "A valid message encoder factory must be passed to the GZipEncoder");
        encoder = new GZipMessageEncoder(messageEncoderFactory.Encoder, this);
    }
    
  3. 这就是我调用服务的方式:

       var requestClient = new BulkRequestTransmitterPortTypeClient("BulkRequestTransmitterPort");
    
            requestClient.Endpoint.Contract.ProtectionLevel = System.Net.Security.ProtectionLevel.None;
     #if DEBUG
            var vs = requestClient.Endpoint.Behaviors.Where((i) => i.GetType().Namespace.Contains("VisualStudio"));
            if( vs!=null )
             requestClient.Endpoint.Behaviors.Remove((System.ServiceModel.Description.IEndpointBehavior)vs.Single());
    #endif                
       using (var scope = new OperationContextScope(requestClient.InnerChannel))
            {
                 //Adding proper HTTP Header to an outgoing requqest.
                HttpRequestMessageProperty requestMessage = new HttpRequestMessageProperty();
    
                requestMessage.Headers["Content-Encoding"] = "gzip";
                requestMessage.Headers["Content-Type"] = @"multipart/related; type=""application/xop+xml"";start=""<Here goes envelope boundary id>"";start-info=""text/xml"";boundary=""here goes boundary id""";
                OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = requestMessage;
    
                response = requestClient.BulkRequestTransmitter(request.ACASecurityHeader,
                                                                    request.Security, ref request.ACABusinessHeader,
                                                                    request.ACATransmitterManifestReqDtl, 
                                                                    request.ACABulkRequestTransmitter);
            }
    
  4. 修改 Mime 部分:

9.1。添加新方法:

    public void GetHeader(StringBuilder Builder)
    {
        if (string.IsNullOrEmpty(ContentId) && string.IsNullOrEmpty(ContentType) && string.IsNullOrEmpty(TransferEncoding))
            return;

        if (!string.IsNullOrEmpty(ContentTypeStart))
        {
            Builder.Append(string.Format("Content-Type: {0}", ContentTypeStart));
            Builder.Append(string.Format("; type=\"{0}\"", ContentType));
        }
        else
            Builder.Append(string.Format("Content-Type: {0}", ContentType));

        if (!string.IsNullOrEmpty(CharSet)) Builder.Append(string.Format("; charset={0}", CharSet));
        Builder.Append(new char[] { '\r', '\n' });
        Builder.Append(string.Format("Content-Transfer-Encoding: {0}", TransferEncoding));
        Builder.Append(new char[] { '\r', '\n' });
        Builder.Append(string.Format("Content-Id: {0}", ContentId));
        Builder.Append(new char[] { '\r', '\n' });
        if (!string.IsNullOrEmpty(ContentDisposition))
            Builder.Append(string.Format("Content-Disposition: attachment; filename=\"{0}\"", ContentDisposition));
    }

9.2. 添加属性:

   public string ContentDisposition { get; set; }
  1. 修改 MimeParser SerializeMimeContent() 方法:替换这块代码:

           Builder.Append(string.Format("Content-Type: {0}", item.ContentType));
            if (!string.IsNullOrEmpty(item.CharSet)) Builder.Append(string.Format("; charset={0}", item.CharSet));
            Builder.Append(new char[] { '\r', '\n' });
            Builder.Append(string.Format("Content-Transfer-Encoding: {0}", item.TransferEncoding));
            Builder.Append(new char[] { '\r', '\n' });
            Builder.Append(string.Format("Content-Id: {0}", item.ContentId));
    

有了这个:

item.GetHeader(Builder);

应该就是这样!踢掉你的鞋子,挖掘蓝调!:)))

于 2016-03-16T15:10:29.207 回答
3

首先,快速免责声明。这个答案是由fatherOfWine、Russ 和 Bon 在这个问题和其他 SO 问题中提供的好东西提供的。我真正做的只是结合他们的一堆东西,并解决我仍然遇到的问题,直到它起作用。更重要的是,这里提供的代码很糟糕,可能不应该按原样使用。既然我知道什么是有效的,我打算彻底清理它,我建议任何人使用它来做同样的事情。任何看到这一点的人都可能会想到的一件大事是我使用过多的静态变量作为快速破解来通过管道获取所有内容。说真的,不要在生产中使用它,这是将东西扔到墙上直到有东西卡住的几个小时的产物,但它应该提供一个很好的起点,让事情变得更好。


代码太多,无法在此处真正包含所有内容,因此我将仅介绍一些重点和一般发现,然后包含指向 VS 解决方案的链接。

  1. 确保您已经设置了 TCC 和各种其他 ID,您购买了正确类型的证书(本文档的第 41 页)并且您已正确注册证书(请参阅本文档
  2. 我发现删除肥皂信封中的所有 CR-LF 是让消息被接受的必要条件。有了它们,我会在“意外子元素”或类似的某些元素上遇到错误。
  3. 该文档在几个地方自相矛盾(请参阅第7484页,并查看他们所说的 BulkExchangeFile 元素应包含的内容作为示例),并且 wsdl/xsds 也完全是错误的。也许我只是不知何故有旧的,但我必须做出改变并尝试一些事情,直到我发现他们这边的服务实际上会接受什么。
  4. 正确地将 keyinfo 添加到 signedxml 部分非常重要,您的所有引用都正确构建并包含正确的 InclusiveNamespaces 列表,并且一旦您调用 ComputeSignature,您对信封所做的唯一更改就是添加签名元素。
  5. 说到签名元素,如果它出现在安全元素内的时间戳元素之后,IRS 系统将返回错误。它必须是第一个。
  6. 因为命名空间前缀在生成签名引用时非常重要,所以我采用了手动构建信封 xml 的路线,因此我可以确定所有内容都与他们想要的完全匹配。即便如此,有几个元素的前缀我必须在测试时更改,因为 XSD 或文档中的某些页面所说的应该不是他们的服务真正想要的。幸运的是,服务返回的错误实际上提供了一些帮助,通过指示它期望来自哪个命名空间的值。
  7. 除了设置所有 gzip 和 MTOM 的东西(再次感谢 100 万美元的父亲葡萄酒的帮助)之外,最终对我有用的大部分是在单个通用类(我巧妙地称之为“通用”)中完成的。同样,这是一个糟糕的代码,只是需要让某些东西(任何东西!)正常工作的产物。我将继续并将其包含在答案中,以防万一它提供一个快速的“啊哈!” 给其他解决这个问题的人。

    using System;
    using System.IO;
    using System.Net;
    using System.Security.Cryptography.X509Certificates;
    using System.Security.Cryptography.Xml;
    using System.ServiceModel;
    using System.ServiceModel.Channels;
    using System.Text;
    using System.Xml;
    using IrsAcaClient.ACABulkRequestTransmitterService;
    
    namespace IrsAcaClient
    {
    public class General
    {
        /*****************************************************
         * 
         * What I'm doing here (with static vars) is VERY BAD but this whole thing is just a dirty hack for now.
         * Hopefully I can clean this up later.
         * - JRS 2016-05-10
         * 
         *****************************************************/
        public const string SecurityTimestampStringFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffZ";
    
        public const string EnvelopeContentID = "<rootpart>";
    
        public static string AttachmentFilePath;
    
        public static string AttachmentFileName { get { return Path.GetFileName(General.AttachmentFilePath); } }
        public static string AttachmentContentID {get { return string.Format("<{0}>", General.AttachmentFileName); }}
    
        public const string MIMEBoundary = "MIME_boundary";
    
        public static string TCCode;
    
        public static Guid TransmissionGuid;
    
        public static string UniqueTransmissionId
        {
            get { return string.Format("{0}:SYS12:{1}::T", TransmissionGuid, TCCode); }
        }
    
        public static string SecurityTimeStampWsuId;
        public static string ManifestWsuId;
        public static string BusinessHeaderWsuId;
        public static string SignatureWsuId;
    
        public static string CertificatePath;
        public static string CertificatePassword;
    
        public static DateTime SecurityTimestampUTC;
    
        private static string _replacementSoapEnvelope;
    
        public static string ReplacementSoapEnvelope{get { return _replacementSoapEnvelope; }}
    
        private static void GenerateReference(string elementID, string inclusivePrefixList, SignedXmlWithId xSigned)
        {
            var reference = new Reference()
            {
                Uri = "#" + elementID
            };
    
            XmlDsigExcC14NTransform env = new XmlDsigExcC14NTransform();
            env.InclusiveNamespacesPrefixList = inclusivePrefixList;
            reference.AddTransform(env);
    
            xSigned.AddReference(reference);
        }
    
        public static string GetAttachmentFileContent()
        {
            //probably not ideal
            return File.ReadAllText(AttachmentFilePath);
        }
    
        public static string GetFileName()
        {
            //TODO: this may need to be tweaked slightly from the real filename
            return General.AttachmentFileName;
        }
    
        public static string GenerateWsuId(string prefix)
        {
            return string.Format("{0}-{1}", prefix, Guid.NewGuid().ToString().Replace("-", "").ToUpper());
        }
    
        internal static void GenerateReplacementSoapEnvelope(ACABulkRequestTransmitterService.SecurityHeaderType securityHeader, ACABulkRequestTransmitterService.ACABulkBusinessHeaderRequestType businessHeader, ACABulkRequestTransmitterService.ACATrnsmtManifestReqDtlType manifest, ACABulkRequestTransmitterService.ACABulkRequestTransmitterType bulkTrans)
        {
            //load the base envelope xml
            var doc = new XmlDocument();
            doc.PreserveWhitespace = false;
            doc.Load("BaseSoapEnvelope.xml");
    
            /* Need a bunch of namespaces defined
             * xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
             * xmlns:urn="urn:us:gov:treasury:irs:ext:aca:air:7.0"
             * xmlns:urn1="urn:us:gov:treasury:irs:common"
             * xmlns:urn2="urn:us:gov:treasury:irs:msg:acabusinessheader"
             * xmlns:urn3="urn:us:gov:treasury:irs:msg:irsacabulkrequesttransmitter"
             * xmlns:wsa="http://www.w3.org/2005/08/addressing"
             * 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"
             * xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
             * xmlns:xop="http://www.w3.org/2004/08/xop/include"
             */
            XmlNamespaceManager nsMgr = new XmlNamespaceManager(doc.NameTable);
            nsMgr.AddNamespace("soapenv", "http://schemas.xmlsoap.org/soap/envelope/");
            nsMgr.AddNamespace("urn", "urn:us:gov:treasury:irs:ext:aca:air:7.0");
            nsMgr.AddNamespace("urn1", "urn:us:gov:treasury:irs:common");
            nsMgr.AddNamespace("urn2", "urn:us:gov:treasury:irs:msg:acabusinessheader");
            nsMgr.AddNamespace("urn3", "urn:us:gov:treasury:irs:msg:irsacabulkrequesttransmitter");
            nsMgr.AddNamespace("wsa", "http://www.w3.org/2005/08/addressing");
            nsMgr.AddNamespace("wsse", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
            nsMgr.AddNamespace("wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");
            nsMgr.AddNamespace("ds", "http://www.w3.org/2000/09/xmldsig#");
            nsMgr.AddNamespace("xop","http://www.w3.org/2004/08/xop/include");
    
    
            //start replacing values in it
            //for securityHeader, should have the following
            /*
             * securityHeader.Signature.Id
             * securityHeader.Timestamp.Id
             * securityHeader.Timestamp.Created.Value
             * securityHeader.Timestamp.Expires.Value
             */
            //doc.SelectSingleNode("//wsse:Security/ds:Signature", nsMgr).Attributes["Id"].Value = securityHeader.Signature.Id;
            doc.SelectSingleNode("//wsse:Security/wsu:Timestamp", nsMgr).Attributes["wsu:Id"].Value = securityHeader.Timestamp.Id;
            doc.SelectSingleNode("//wsse:Security/wsu:Timestamp/wsu:Created", nsMgr).InnerText = securityHeader.Timestamp.Created.Value;
            doc.SelectSingleNode("//wsse:Security/wsu:Timestamp/wsu:Expires", nsMgr).InnerText = securityHeader.Timestamp.Expires.Value;
    
    
            //for businessHeader, should have the following
            /*
             * businessHeader.UniqueTransmissionId
             * businessHeader.Timestamp
             * businessHeader.Id 
             */
            doc.SelectSingleNode("//urn2:ACABusinessHeader", nsMgr).Attributes["wsu:Id"].Value = businessHeader.Id;
            doc.SelectSingleNode("//urn2:ACABusinessHeader/urn:UniqueTransmissionId", nsMgr).InnerText = businessHeader.UniqueTransmissionId;
            doc.SelectSingleNode("//urn2:ACABusinessHeader/urn1:Timestamp", nsMgr).InnerText = businessHeader.Timestamp.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ssZ");
    
    
            //for manifest, should have the following, some of which will need some conversions
            /*
             * manifest.Id
             * manifest.BinaryFormatCd - convert from enum
             * manifest.PaymentYr
             * manifest.PriorYearDataInd - convert from enum
             * manifest.EIN
             * manifest.TransmissionTypeCd - convert from enum
             * manifest.TestFileCd
             * manifest.TransmitterNameGrp.BusinessNameLine1Txt
             * manifest.CompanyInformationGrp.CompanyNm
             * manifest.CompanyInformationGrp.MailingAddressGrp.Item.AddressLine1Txt
             * manifest.CompanyInformationGrp.MailingAddressGrp.Item.CityNm
             * manifest.CompanyInformationGrp.MailingAddressGrp.Item.USStateCd - convert from enum
             * manifest.CompanyInformationGrp.MailingAddressGrp.Item.USZIPCd
             * manifest.CompanyInformationGrp.ContactNameGrp.PersonFirstNm
             * manifest.CompanyInformationGrp.ContactNameGrp.PersonLastNm
             * manifest.CompanyInformationGrp.ContactPhoneNum
             * manifest.VendorInformationGrp.VendorCd
             * manifest.VendorInformationGrp.ContactNameGrp.PersonFirstNm
             * manifest.VendorInformationGrp.ContactNameGrp.PersonLastNm
             * manifest.VendorInformationGrp.ContactPhoneNum
             * manifest.TotalPayeeRecordCnt
             * manifest.TotalPayerRecordCnt
             * manifest.SoftwareId
             * manifest.FormTypeCd - convert from enum
             * manifest.ChecksumAugmentationNum
             * manifest.AttachmentByteSizeNum
             * manifest.DocumentSystemFileNm
             */
            doc.SelectSingleNode("//urn:ACATransmitterManifestReqDtl", nsMgr).Attributes["wsu:Id"].Value = manifest.Id;
            doc.SelectSingleNode("//urn:ACATransmitterManifestReqDtl/urn:PaymentYr", nsMgr).InnerText = manifest.PaymentYr;
            doc.SelectSingleNode("//urn:ACATransmitterManifestReqDtl/urn:PriorYearDataInd", nsMgr).InnerText = manifest.PriorYearDataInd.GetXmlEnumAttributeValueFromEnum();
            doc.SelectSingleNode("//urn:ACATransmitterManifestReqDtl/urn1:EIN", nsMgr).InnerText = manifest.EIN;
            doc.SelectSingleNode("//urn:ACATransmitterManifestReqDtl/urn:TransmissionTypeCd", nsMgr).InnerText = manifest.TransmissionTypeCd.ToString();
            doc.SelectSingleNode("//urn:ACATransmitterManifestReqDtl/urn:TestFileCd", nsMgr).InnerText = manifest.TestFileCd;
            doc.SelectSingleNode("//urn:ACATransmitterManifestReqDtl/urn:TransmitterNameGrp/urn:BusinessNameLine1Txt", nsMgr).InnerText = manifest.TransmitterNameGrp.BusinessNameLine1Txt;
            doc.SelectSingleNode("//urn:ACATransmitterManifestReqDtl/urn:CompanyInformationGrp/urn:CompanyNm", nsMgr).InnerText = manifest.CompanyInformationGrp.CompanyNm;
            doc.SelectSingleNode("//urn:ACATransmitterManifestReqDtl/urn:CompanyInformationGrp/urn:MailingAddressGrp/urn:USAddressGrp/urn:AddressLine1Txt", nsMgr).InnerText = ((USAddressGrpType)manifest.CompanyInformationGrp.MailingAddressGrp.Item).AddressLine1Txt;
            doc.SelectSingleNode("//urn:ACATransmitterManifestReqDtl/urn:CompanyInformationGrp/urn:MailingAddressGrp/urn:USAddressGrp/urn1:CityNm", nsMgr).InnerText = ((USAddressGrpType)manifest.CompanyInformationGrp.MailingAddressGrp.Item).CityNm;
            doc.SelectSingleNode("//urn:ACATransmitterManifestReqDtl/urn:CompanyInformationGrp/urn:MailingAddressGrp/urn:USAddressGrp/urn:USStateCd", nsMgr).InnerText = ((USAddressGrpType)manifest.CompanyInformationGrp.MailingAddressGrp.Item).USStateCd.ToString();
            doc.SelectSingleNode("//urn:ACATransmitterManifestReqDtl/urn:CompanyInformationGrp/urn:MailingAddressGrp/urn:USAddressGrp/urn1:USZIPCd", nsMgr).InnerText = ((USAddressGrpType)manifest.CompanyInformationGrp.MailingAddressGrp.Item).USZIPCd;
            doc.SelectSingleNode("//urn:ACATransmitterManifestReqDtl/urn:CompanyInformationGrp/urn:ContactNameGrp/urn:PersonFirstNm", nsMgr).InnerText = manifest.CompanyInformationGrp.ContactNameGrp.PersonFirstNm;
            doc.SelectSingleNode("//urn:ACATransmitterManifestReqDtl/urn:CompanyInformationGrp/urn:ContactNameGrp/urn:PersonLastNm", nsMgr).InnerText = manifest.CompanyInformationGrp.ContactNameGrp.PersonLastNm;
            doc.SelectSingleNode("//urn:ACATransmitterManifestReqDtl/urn:CompanyInformationGrp/urn:ContactPhoneNum", nsMgr).InnerText = manifest.CompanyInformationGrp.ContactPhoneNum;
            doc.SelectSingleNode("//urn:ACATransmitterManifestReqDtl/urn:VendorInformationGrp/urn:VendorCd", nsMgr).InnerText = manifest.VendorInformationGrp.VendorCd;
            doc.SelectSingleNode("//urn:ACATransmitterManifestReqDtl/urn:VendorInformationGrp/urn:ContactNameGrp/urn:PersonFirstNm", nsMgr).InnerText = manifest.VendorInformationGrp.ContactNameGrp.PersonFirstNm;
            doc.SelectSingleNode("//urn:ACATransmitterManifestReqDtl/urn:VendorInformationGrp/urn:ContactNameGrp/urn:PersonLastNm", nsMgr).InnerText = manifest.VendorInformationGrp.ContactNameGrp.PersonLastNm;
            doc.SelectSingleNode("//urn:ACATransmitterManifestReqDtl/urn:VendorInformationGrp/urn:ContactPhoneNum", nsMgr).InnerText = manifest.VendorInformationGrp.ContactPhoneNum;
            doc.SelectSingleNode("//urn:ACATransmitterManifestReqDtl/urn:TotalPayeeRecordCnt", nsMgr).InnerText = manifest.TotalPayeeRecordCnt;
            doc.SelectSingleNode("//urn:ACATransmitterManifestReqDtl/urn:TotalPayerRecordCnt", nsMgr).InnerText = manifest.TotalPayerRecordCnt;
            doc.SelectSingleNode("//urn:ACATransmitterManifestReqDtl/urn:SoftwareId", nsMgr).InnerText = manifest.SoftwareId;
            doc.SelectSingleNode("//urn:ACATransmitterManifestReqDtl/urn:FormTypeCd", nsMgr).InnerText = manifest.FormTypeCd.GetXmlEnumAttributeValueFromEnum();
            doc.SelectSingleNode("//urn:ACATransmitterManifestReqDtl/urn1:BinaryFormatCd", nsMgr).InnerText = manifest.BinaryFormatCd.GetXmlEnumAttributeValueFromEnum();
            doc.SelectSingleNode("//urn:ACATransmitterManifestReqDtl/urn1:ChecksumAugmentationNum", nsMgr).InnerText = manifest.ChecksumAugmentationNum;
            doc.SelectSingleNode("//urn:ACATransmitterManifestReqDtl/urn1:AttachmentByteSizeNum", nsMgr).InnerText = manifest.AttachmentByteSizeNum;
            doc.SelectSingleNode("//urn:ACATransmitterManifestReqDtl/urn:DocumentSystemFileNm", nsMgr).InnerText = manifest.DocumentSystemFileNm;
    
    
            //for bulkTrans, should have the following
            /*
             * bulkTrans.BulkExchangeFile.Include.href
             */
            doc.SelectSingleNode("//urn3:ACABulkRequestTransmitter/urn1:BulkExchangeFile/xop:Include", nsMgr).Attributes["href"].Value = bulkTrans.BulkExchangeFile.Include.href;
    
    
            //now do some more security setup
            var cert = new X509Certificate2(CertificatePath, CertificatePassword, X509KeyStorageFlags.MachineKeySet);
    
            var exported = cert.Export(X509ContentType.Cert, CertificatePassword);
            var base64 = Convert.ToBase64String(exported);
    
            //now compute all the signing stuff
            var xSigned = new SignedXmlWithId(doc);
            xSigned.Signature.Id = securityHeader.Signature.Id;
    
            // Add the key to the SignedXml document.
            xSigned.SigningKey = cert.PrivateKey;
            xSigned.Signature.Id = SignatureWsuId;
            xSigned.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NWithCommentsTransformUrl;
    
            var keyInfo = new KeyInfo
            {
                Id = GenerateWsuId("KI")
            };
    
            //need to get the keyinfo into the signed xml stuff before we compute sigs, and because it is using some stuff that
            //doesn't appear to be supported out of the box we'll work around it by adding a node directly
            var sbKeyInfo = new StringBuilder();
            sbKeyInfo.Append("<root 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\" xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\">");
            sbKeyInfo.Append("<wsse:SecurityTokenReference wsu:Id=\"" + GenerateWsuId("STR") + "\">");
            sbKeyInfo.Append("<wsse:KeyIdentifier EncodingType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary\" ValueType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3\">" + base64.ToString());
            sbKeyInfo.Append("</wsse:KeyIdentifier>");
            sbKeyInfo.Append("</wsse:SecurityTokenReference>");
            sbKeyInfo.Append("</root>");
            XmlDocument tempDoc = new XmlDocument();
            tempDoc.LoadXml(sbKeyInfo.ToString());
    
            keyInfo.AddClause(new KeyInfoNode((XmlElement)tempDoc.FirstChild.FirstChild));
    
            xSigned.KeyInfo = keyInfo;
    
            GenerateReference(SecurityTimeStampWsuId, "wsse wsa soapenv urn urn1 urn2 urn3", xSigned);
            GenerateReference(BusinessHeaderWsuId, "wsa soapenv urn urn1 urn3", xSigned);
            GenerateReference(ManifestWsuId, "wsa soapenv urn1 urn2 urn3", xSigned);
    
            // Compute the Signature.
            xSigned.ComputeSignature();
    
            //signing stuff must come before the timestamp or the IRS service complains
            doc.SelectSingleNode("//wsse:Security", nsMgr).InsertBefore(xSigned.GetXml(), doc.SelectSingleNode("//wsse:Security", nsMgr).FirstChild);
    
            //
            _replacementSoapEnvelope = doc.OuterXml;
        }
    
        public static ACABulkRequestTransmitterResponseType Run(ACABulkRequestTransmitterService.SecurityHeaderType securityHeader, ACABulkRequestTransmitterService.ACABulkBusinessHeaderRequestType businessHeader, ACABulkRequestTransmitterService.ACATrnsmtManifestReqDtlType manifest, ACABulkRequestTransmitterService.ACABulkRequestTransmitterType bulkTrans)
        {
            //had some issues early on with the cert on the IRS server, this should probably be removed and retested without it
            ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, errors) => true;
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Ssl3 |
                                                   SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
    
            var acaSecurityHeader = new ACABulkRequestTransmitterService.TransmitterACASecurityHeaderType(); //leave this empty for transmitting via ISS-A2A
    
            var requestClient = new ACABulkRequestTransmitterService.BulkRequestTransmitterPortTypeClient("BulkRequestTransmitterPort");
    
            requestClient.Endpoint.Contract.ProtectionLevel = System.Net.Security.ProtectionLevel.None;
            //var vs = requestClient.Endpoint.Behaviors.Where((i) => i.GetType().Namespace.Contains("VisualStudio"));
            //if (vs != null)
            //    requestClient.Endpoint.Behaviors.Remove((System.ServiceModel.Description.IEndpointBehavior)vs.Single());
    
            //generate the real envelope we want
            GenerateReplacementSoapEnvelope(securityHeader, businessHeader, manifest, bulkTrans);
    
            using (var scope = new OperationContextScope(requestClient.InnerChannel))
            {
    
                //Adding proper HTTP Header to an outgoing requqest.
                HttpRequestMessageProperty requestMessage = new HttpRequestMessageProperty();
    
                requestMessage.Headers["Content-Encoding"] = "gzip";
                requestMessage.Headers["Content-Type"] = string.Format(@"multipart/related; type=""application/xop+xml"";start=""{0}"";start-info=""text/xml"";boundary=""{1}""", General.EnvelopeContentID, General.MIMEBoundary);
                OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = requestMessage;
    
                var response = requestClient.BulkRequestTransmitter(acaSecurityHeader,
                                                                    securityHeader,
                                                                    ref businessHeader,
                                                                    manifest,
                                                                    bulkTrans);
    
                //we got a response!  now do something with it
                return response;
    
            }
        }
    }
    

这是完整的解决方案,只需要提供您自己的所有数据(包括包含所有收款人和付款人记录的完整附件文件,这超出了此范围,但应该很容易生成)。另请注意,这只是提交表格,而不是状态检查。当我开始工作时,我会尽量记住返回并更新这个答案(但如果其他人已经拥有它并且想要分享,那也很不错)。


编辑状态服务

我结合了从 wsdl 生成的类的清理版本和我自己的垃圾代码来获取消息并处理响应。请注意,这还没有经过 100% 的测试,需要进行健全性检查等,但就像以前的东西一样,至少应该可以帮助其他任何在这个混乱中挣扎的人。这里的用法非常简单:

var statusResponse = StatusService.CheckStatus(receipt, tCCode, certificatePath, certificatePassword, "https://la.www4.irs.gov/airp/aca/a2a/1095BC_Status_Request_AATS2016");

这是完整的类(带有奖励生成的类名称空间):

有关状态服务代码,请参阅我的第二个答案

于 2016-05-20T13:25:11.253 回答
2

秒回答包括状态服务,而不仅仅是另一个可能消失的链接。

这是主要课程:

using System;
using System.IO;
using System.IO.Compression;
using System.Net;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography.Xml;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Serialization;

namespace IrsAcaClient
{
    public class StatusService
    {
        private const string SecurityTimestampStringFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffZ";


        public static ACABulkRequestStatusService.ACABulkRequestTransmitterStatusDetailResponseType CheckStatus(string receiptID, string tCCode, string certificatePath, string certificatePassword, string statusServiceUrl)
        {
            //go ahead and generate some of the ids and timestamps we'll need
            var securityTimeStampWsuId = GenerateWsuId("TS");
            var businessHeaderWsuId = GenerateWsuId("id");
            var detailRequestWsuId = GenerateWsuId("id");
            var signatureWsuId = GenerateWsuId("SIG");

            var securityTimestampUTC = DateTime.UtcNow;
            var securityTimestampCreated = securityTimestampUTC.ToString(SecurityTimestampStringFormat);
            var securityTimestampExpires = securityTimestampUTC.AddMinutes(10).ToString(SecurityTimestampStringFormat);

            //build the envelope
            //load the base envelope xml
            var doc = new XmlDocument();
            doc.PreserveWhitespace = false;
            doc.Load("BaseStatusRequestEnvelope.xml");

            /* Need a bunch of namespaces defined
             * xmlns:oas1="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
             * xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
             * xmlns:urn="urn:us:gov:treasury:irs:msg:irstransmitterstatusrequest"
             * xmlns:urn1="urn:us:gov:treasury:irs:ext:aca:air:7.0" 
             * xmlns:urn2="urn:us:gov:treasury:irs:common"
             * xmlns:urn3="urn:us:gov:treasury:irs:msg:acasecurityheader"
             * xmlns:wsa="http://www.w3.org/2005/08/addressing"
             * 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"
             * xmlns:ds="http://www.w3.org/2000/09/xmldsig#");
             */
            XmlNamespaceManager nsMgr = new XmlNamespaceManager(doc.NameTable);
            nsMgr.AddNamespace("soapenv", "http://schemas.xmlsoap.org/soap/envelope/");
            nsMgr.AddNamespace("urn", "urn:us:gov:treasury:irs:msg:irstransmitterstatusrequest");
            nsMgr.AddNamespace("urn1", "urn:us:gov:treasury:irs:ext:aca:air:7.0");
            nsMgr.AddNamespace("urn2", "urn:us:gov:treasury:irs:common");
            nsMgr.AddNamespace("urn3", "urn:us:gov:treasury:irs:msg:acasecurityheader");
            nsMgr.AddNamespace("wsa", "http://www.w3.org/2005/08/addressing");
            nsMgr.AddNamespace("wsse", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
            nsMgr.AddNamespace("wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");
            nsMgr.AddNamespace("oas1", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
            nsMgr.AddNamespace("ds", "http://www.w3.org/2000/09/xmldsig#");

            //start replacing values in it
            //for securityHeader, should have the following
            /*
             * securityHeader.Timestamp.Id
             * securityHeader.Timestamp.Created.Value
             * securityHeader.Timestamp.Expires.Value
             */
            doc.SelectSingleNode("//wsse:Security/wsu:Timestamp", nsMgr).Attributes["wsu:Id"].Value = securityTimeStampWsuId;
            doc.SelectSingleNode("//wsse:Security/wsu:Timestamp/wsu:Created", nsMgr).InnerText = securityTimestampCreated;
            doc.SelectSingleNode("//wsse:Security/wsu:Timestamp/wsu:Expires", nsMgr).InnerText = securityTimestampExpires;

            //for businessHeader, should have the following
            /*
             * businessHeader.UniqueTransmissionId
             * businessHeader.Timestamp
             * businessHeader.Id 
             */
            doc.SelectSingleNode("//urn:ACABusinessHeader", nsMgr).Attributes["wsu:Id"].Value = businessHeaderWsuId;
            doc.SelectSingleNode("//urn:ACABusinessHeader/urn1:UniqueTransmissionId", nsMgr).InnerText = GetUniqueTransmissionId(Guid.NewGuid(), tCCode);
            doc.SelectSingleNode("//urn:ACABusinessHeader/urn2:Timestamp", nsMgr).InnerText = securityTimestampUTC.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ssZ");

            //for ACABulkRequestTransmitterStatusDetailRequest, should have the following
            /*
             * ACABulkRequestTransmitterStatusDetailRequest.Id
             * ACABulkRequestTransmitterStatusDetailRequest.ACABulkReqTrnsmtStsReqGrpDtl.ReceiptId
             */
            doc.SelectSingleNode("//urn:ACABulkRequestTransmitterStatusDetailRequest", nsMgr).Attributes["wsu:Id"].Value = detailRequestWsuId;
            doc.SelectSingleNode("//urn:ACABulkRequestTransmitterStatusDetailRequest/urn1:ACABulkReqTrnsmtStsReqGrpDtl/urn2:ReceiptId", nsMgr).InnerText = receiptID;

            //now do some more security setup
            var cert = new X509Certificate2(certificatePath, certificatePassword, X509KeyStorageFlags.MachineKeySet);

            var exported = cert.Export(X509ContentType.Cert, certificatePassword);
            var base64 = Convert.ToBase64String(exported);

            //now compute all the signing stuff
            var xSigned = new SignedXmlWithId(doc);

            // Add the key to the SignedXml document.
            xSigned.SigningKey = cert.PrivateKey;
            xSigned.Signature.Id = signatureWsuId;
            xSigned.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NWithCommentsTransformUrl;

            var keyInfo = new KeyInfo
            {
                Id = GenerateWsuId("KI")
            };

            //need to get the keyinfo into the signed xml stuff before we compute sigs, and because it is using some stuff that
            //doesn't appear to be supported out of the box we'll work around it by adding a node directly
            var sbKeyInfo = new StringBuilder();
            sbKeyInfo.Append("<root 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\" xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\">");
            sbKeyInfo.Append("<wsse:SecurityTokenReference wsu:Id=\"" + GenerateWsuId("STR") + "\">");
            sbKeyInfo.Append("<wsse:KeyIdentifier EncodingType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary\" ValueType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3\">" + base64.ToString());
            sbKeyInfo.Append("</wsse:KeyIdentifier>");
            sbKeyInfo.Append("</wsse:SecurityTokenReference>");
            sbKeyInfo.Append("</root>");
            XmlDocument tempDoc = new XmlDocument();
            tempDoc.LoadXml(sbKeyInfo.ToString());

            keyInfo.AddClause(new KeyInfoNode((XmlElement)tempDoc.FirstChild.FirstChild));

            xSigned.KeyInfo = keyInfo;

            GenerateReference(securityTimeStampWsuId, "wsse wsa oas1 soapenv urn urn1 urn2 urn3", xSigned);
            GenerateReference(businessHeaderWsuId, "wsa oas1 soapenv urn1 urn2 urn3", xSigned);
            GenerateReference(detailRequestWsuId, "oas1 soapenv urn1 urn2 urn3", xSigned);

            // Compute the Signature.
            xSigned.ComputeSignature();

            //signing stuff must come before the timestamp or the IRS service complains
            doc.SelectSingleNode("//wsse:Security", nsMgr).InsertBefore(xSigned.GetXml(), doc.SelectSingleNode("//wsse:Security", nsMgr).FirstChild);

            //get the completed envelope
            var envelope = doc.OuterXml;

            //start the webrequest
            //get the request object
            var request = CreateWebRequest(statusServiceUrl);

            //get the request stream and then get a writer on it
            using (var stream = request.GetRequestStream())
            using (var gz = new GZipStream(stream, CompressionMode.Compress))
            using (var writer = new StreamWriter(gz))
            {
                //start by writing the soap envelope to the stream
                writer.WriteLine(envelope);
                writer.Close();
                stream.Close();
            }

            //get the response
            WebResponse response;

            //let an exception get thrown up the stack
            response = request.GetResponse();

            //get the response stream, get a reader on it, and read the response as text
            using (var responseStream = response.GetResponseStream())
            using (var reader = new StreamReader(responseStream, Encoding.UTF8))
            {
                var responseText = reader.ReadToEnd();

                //rip the one element (and children) we need out
                var match = Regex.Match(responseText, @"<(?'prefix'[\w\d]*):ACABulkRequestTransmitterStatusDetailResponse.*<\/\k<prefix>:ACABulkRequestTransmitterStatusDetailResponse>");

                return Deserialize<ACABulkRequestStatusService.ACABulkRequestTransmitterStatusDetailResponseType>(match.ToString());
            }
        }

        private static string GetUniqueTransmissionId(Guid transmissionGuid, string tCCode)
        {
            return string.Format("{0}:SYS12:{1}::T", transmissionGuid, tCCode);
        }

        private static string GenerateWsuId(string prefix)
        {
            return string.Format("{0}-{1}", prefix, Guid.NewGuid().ToString().Replace("-", "").ToUpper());
        }

        private static void GenerateReference(string elementID, string inclusivePrefixList, SignedXmlWithId xSigned)
        {
            var reference = new Reference()
            {
                Uri = "#" + elementID
            };

            XmlDsigExcC14NTransform env = new XmlDsigExcC14NTransform();
            env.InclusiveNamespacesPrefixList = inclusivePrefixList;
            reference.AddTransform(env);

            xSigned.AddReference(reference);
        }

        /// <summary>
        /// creates a webrequest object and prefills some required headers and such
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        private static HttpWebRequest CreateWebRequest(string url)
        {
            //setup a web request with all the headers and such that the service requires
            var webRequest = (HttpWebRequest)WebRequest.Create(url);

            webRequest.Method = "POST";
            webRequest.ProtocolVersion = HttpVersion.Version11;
            webRequest.Headers.Add(HttpRequestHeader.ContentEncoding, "gzip");
            webRequest.Headers.Add(HttpRequestHeader.AcceptEncoding, "gzip, deflate");
            webRequest.ContentType = "text/xml;charset=UTF-8";
            webRequest.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
            webRequest.Headers.Add("SOAPAction", "RequestSubmissionStatusDetail");
            webRequest.KeepAlive = true;

            return webRequest;
        }

        /// <summary>
        /// deserializes the xml string into an object
        /// </summary>
        /// <param name="xmlString"></param>
        /// <returns></returns>
        public static T Deserialize<T>(string xmlString) where T : class
        {
            //if the string is empty, just return null
            if (xmlString.Length <= 0)
            {
                return null;
            }

            //create a serializer
            var serializer = new System.Xml.Serialization.XmlSerializer(typeof(T));
            T output;
            //create the reader that the serializer will read from, passing it the string
            using (var reader = new System.IO.StringReader(xmlString))
            {
                //rebuild the list object
                output = (T)serializer.Deserialize(reader);
            }
            //return the list
            return output;
        }
    }
}

这是相关的基础xml:

<?xml version="1.0" encoding="utf-8" ?>
<soapenv:Envelope
xmlns:oas1="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:urn="urn:us:gov:treasury:irs:msg:irstransmitterstatusrequest"
xmlns:urn1="urn:us:gov:treasury:irs:ext:aca:air:7.0" xmlns:urn2="urn:us:gov:treasury:irs:common"
xmlns:urn3="urn:us:gov:treasury:irs:msg:acasecurityheader">
  <soapenv:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
    <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">
      <wsu:Timestamp wsu:Id="XXXXXXXXXXXXXXXXXX">
        <wsu:Created>XXXXXXXXXXXXXXXXXX</wsu:Created>
        <wsu:Expires>XXXXXXXXXXXXXXXXXX</wsu:Expires>
      </wsu:Timestamp>
    </wsse:Security>
    <urn:ACABusinessHeader wsu:Id="XXXXXXXXXXXXXXXXXX" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
      <urn1:UniqueTransmissionId>
        XXXXXXXXXXXXXXXXXX
      </urn1:UniqueTransmissionId>
      <urn2:Timestamp>XXXXXXXXXXXXXXXXXX</urn2:Timestamp>
    </urn:ACABusinessHeader>
    <urn3:ACASecurityHeader />
    <wsa:Action>RequestSubmissionStatusDetail</wsa:Action>
  </soapenv:Header>
  <soapenv:Body>
    <urn:ACABulkRequestTransmitterStatusDetailRequest version="1.0" wsu:Id="XXXXXXXXXXXXXXXXXX" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
      <urn1:ACABulkReqTrnsmtStsReqGrpDtl>
        <urn2:ReceiptId>XXXXXXXXXXXXXXXXXX</urn2:ReceiptId>
      </urn1:ACABulkReqTrnsmtStsReqGrpDtl>
    </urn:ACABulkRequestTransmitterStatusDetailRequest>
  </soapenv:Body>
</soapenv:Envelope>

对于这个,我需要对 WSDL 生成的类进行的主要更改如下:

    [System.SerializableAttribute()]
    [XmlRoot("ACABulkRequestTransmitterStatusDetailResponse", Namespace = "urn:us:gov:treasury:irs:msg:irstransmitterstatusrequest")]
    public class ACABulkRequestTransmitterStatusDetailResponseType
    {
        private ACABulkRequestTransmitterResponseType aCABulkRequestTransmitterResponseField;
        private ACABulkReqTrnsmtStsRespGrpDtlType aCABulkReqTrnsmtStsRespGrpDtlField;
        private string versionField;
        public ACABulkRequestTransmitterStatusDetailResponseType()
        {
            this.versionField = "1.0";
        }
        [System.Xml.Serialization.XmlElementAttribute(Namespace = "urn:us:gov:treasury:irs:ext:aca:air:7.0", Order = 0)]
        public ACABulkRequestTransmitterResponseType ACABulkRequestTransmitterResponse
        {
            get
            {
                return this.aCABulkRequestTransmitterResponseField;
            }
            set
            {
                this.aCABulkRequestTransmitterResponseField = value;
            }
        }
        [System.Xml.Serialization.XmlElementAttribute(Namespace = "urn:us:gov:treasury:irs:ext:aca:air:7.0", Order = 1)]
        public ACABulkReqTrnsmtStsRespGrpDtlType ACABulkReqTrnsmtStsRespGrpDtl
        {
            get
            {
                return this.aCABulkReqTrnsmtStsRespGrpDtlField;
            }
            set
            {
                this.aCABulkReqTrnsmtStsRespGrpDtlField = value;
            }
        }
        [System.Xml.Serialization.XmlAttributeAttribute()]
        public string version
        {
            get
            {
                return this.versionField;
            }
            set
            {
                this.versionField = value;
            }
        }
    }
于 2016-05-24T20:21:46.687 回答
1

添加 ds 前缀实际上是破坏这一点的原因。SignatureValue 元素包含序列化的 SignedInfo 元素的 x509 散列(这是具有一致空白的地方)。

通过修改 SignedInfo 元素,当 IRS 将您发送的 SignatureValue 哈希与他们使用您上传并与提供的 TCC 关联的证书计算的 SignedInfo 哈希进行比较时,身份验证将失败。

只需删除您对 SignedInfo 元素的修改,一切都会好起来的。这个对我有用。

于 2016-03-19T19:44:36.633 回答
0

对于那些遇到以下错误的人:

AIRMF3002 拒绝传输 - 无法处理您的请求,因为在附件字节大小编号中发生验证失败

IRS 方面似乎存在他们期望的大小(根据文档)和他们实际接受的大小的问题。最初,我有以下代码:

// Size in Bytes of File: This code returns the "Size" located on the File's Property Page.
// Result: TRANSMISSION REJECTED ON INCORRECT FILE SIZE!
manifestHeader.AttachmentByteSizeNum = new FileInfo(FormDataFilePath).Length.ToString();

我用以下代码替换了上面的代码,我收到的错误得到了解决。

// Read the contents of the file, and retrieve the length of the content of the file itself..
// Result: TRANSMISSION WAS ACCEPTED USING THIS FILE SIZE.
manifestHeader.AttachmentByteSizeNum = File.ReadAllText(FormDataFilePath).Length.ToString();

看起来 Web 服务实际上期望的是文件内容的大小,而不是实际文件的大小。与测试场景有关的大小差异约为 3 个字节。我认为这是因为检索文件的大小会添加一些不属于实际内容的额外文件相关信息。

我已经就这个问题通知了美国国税局关于他们的文件。

于 2016-06-17T20:26:43.323 回答
0

这是对上述帖子的修改,为 jstill 的帖子添加了更多信息。不幸的是,同行评审员拒绝了它。

除了对状态Reference.cs文件所做的更改之外,我还必须包括他对提交文件所做的更新BulkExchangeFileType,以使该方法部分起作用。IncludeFileTypeReference.csDeserializer

Deserializer方法将按预期返回TransmissionStatusCdReceiptId元素,但是,它不会ErrorDataFile正确填充元素。

由于此时我无法ErrorDataFile正确填充对象,因此我没有使用该ACABulkRequestTransmitterStatusDetailResponseType对象来捕获从状态 Web 服务返回的响应。相反,我选择将 读ResponseStream入一个string对象并解析(最多)MIME响应的两个部分,并根据需要处理它们。


对 Status 的 Reference.cs 的其他更改

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34283")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace = "urn:us:gov:treasury:irs:common")]
public partial class BulkExchangeFileType : object, System.ComponentModel.INotifyPropertyChanged
{
    private IncludeType includeField;

    /// <remarks/>
    [System.Xml.Serialization.XmlElement(Order = 0, Namespace = "http://www.w3.org/2004/08/xop/include")]
    public IncludeType Include
    {
        get { return this.includeField; }
        set
        {
            this.includeField = value;
            this.RaisePropertyChanged("Include");
        }
    }

    public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
    protected void RaisePropertyChanged(string propertyName)
    {
        System.ComponentModel.PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
        if (propertyChanged != null)
        {
            propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
        }
    }
}

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34283")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.w3.org/2004/08/xop/include")]
public partial class IncludeType : object, System.ComponentModel.INotifyPropertyChanged
{
    private System.Xml.XmlNode[] anyField;
    private string hrefField;

    /// <remarks/>
    [System.Xml.Serialization.XmlTextAttribute()]
    [System.Xml.Serialization.XmlAnyElementAttribute(Order = 0)]
    public System.Xml.XmlNode[] Any
    {
        get { return this.anyField; }
        set
        {
            this.anyField = value;
            this.RaisePropertyChanged("Any");
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlAttributeAttribute(DataType = "string")]
    public string href
    {
        get { return this.hrefField; }
        set
        {
            this.hrefField = value;
            this.RaisePropertyChanged("href");
        }
    } 

    public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
    protected void RaisePropertyChanged(string propertyName)
    {
        System.ComponentModel.PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
        if (propertyChanged != null)
        {
            propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
        }
    }
}
于 2016-05-31T20:27:55.447 回答