IRS-A2A BulkRequestTransmitter消息未正确格式化和/或无法解释

时间:2016-03-15 20:03:15

标签: c# xml soap-client irs

尝试通过BulkRequestTransmitter Web服务提交时,我收到以下错误。对于此消息,组合指南不太有用,当我将SOAP XML与Composition Guide中的SOAP进行比较时,它们似乎是一对一的。我希望另一组眼睛能够看到问题出在哪里。

  

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

我尝试过的事情:

  • 尝试在SOAP信封中提交(和不提供)空格。
  • 尝试使用XML格式的表格数据XML提交。
  • 尝试以base64string格式提交表格数据(此提交内容已提交)。
  • 在Signature元素中添加了ds前缀。使用this SO post以将前缀添加到Signature元素。
  • 在" Pretty Print"中添加了表格数据。格式和根据更新的作文指南(v4.2)。
  • 为“作文指南” 10.3 部分中列出的MIME请求复制了BulkTransmitterService的格式。
  • 创建了两个解决方案:1。)手动创建SOAP请求所需的XML并通过HttpWebRequest对象发送; 2.)使用WSDL的自定义编码器,通过导入项目的Service Reference作为GZip and Mtom Encoding发送提交请求,并手动创建SOAP状态请求所需的XML(通过{发送) {1}})。

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

  • 在签名元素中添加了HttpWebRequest前缀。
  • 在" Pretty Print"中添加了表格数据。格式和根据更新的作文指南(v4.2:第5.4.2节)。

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

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

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

  • SOAP应该有urn:MailingAddressGrpurn:USAddressGrp的孩子。那个孩子应该包含适当的地址元素。我的代码目前缺少urn:ForeignAddressGrp
  • 的直接子代
  • urn:MailingAddressGrp的{​​{1}}值不正确。我还不完全确定它应该是什么。
  • urn1:DocumentSystemFileNm元素存在与我所拥有的Form1094C_Request_[TCC]_yyyyMMddThhmmssfffZ.xml元素相关的问题。架构需要base64Binary类型。

更新#2.5

  • 更新了我的XML生成过程以包含urn1:BulkExchangeFile元素。
  • 发现我在毫秒内有一个额外的字符(四个而不是三个)。一旦我纠正了这一点,同时删除字符串" Form"从文件名的开头,xop:Include的值能够成功验证架构。

更新#3

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

更新#4

  • 根据所做的其他更新更新了完整请求。删除 来自签名的USAddressGrp前缀基于另一个SO用户 反馈。该用户已经无需使用这些请求 在事实和之后将urn1:DocumentSystemFileNm前缀附加到签名 重新计算签名。

    SO用户也确认他的请求正在使用 ds元素被设置为。的子元素 ds元素。

  • 根据“构图指南”第10.3节中的示例确认<inc:Include>标题是正确的。

更新#5

  • 我目前有两个解决方案:一个是手动创建SOAP请求所需的XML并通过<BulkExchangeFile>发送;使用MIME提交请求,使用下面列出的自定义编码器,并手动创建状态的SOAP请求所需的XML。

    在此更新时,解决方案1在提交提交请求时给出了上述错误,并在进行状态请求时给出了以下错误。但是,使用解决方案2时,两个请求(提交和状态)都会在下面给出错误。

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

更新#6

我遇到了一些问题导致我被推迟。我将为您提供详细的细节,但是,我们没有在IRS系统中注册安全证书,也没有正确安装证书,以便我可以通过HttpWebRequest。最后这些事情已经完成,我能够测试从服务器向IRS提交数据(与我没有正确证书的本地机器相比)。不幸的是,我仍然收到下面详述的WS-Security错误。我已根据我目前发送的内容更新了完整请求。

  

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

MIME标头中的所有换行符都是原样的,我相信换行符是预期的。 FormData附件以Pretty Print的形式发送,而SOAP Envelope则不是;此帖子中的SOAP信封的格式是为了便于阅读。

更新#7:

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

完整要求:

WSDL Service Reference

6 个答案:

答案 0 :(得分:4)

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

  1. 首先,时间戳字段的格式错误:一个在 businessheader根本不应包含毫秒。我知道 一个事实。
  2. 在安全标头时间戳中,只允许表示3位数 毫秒。
  3. 从ACATransmitterManifestReqDtl元素中删除“OriginalReceiptId”等空元素:他们不喜欢这些元素。
  4. 我希望你能为他们提供合适的软件ID,因为你在有效载荷中有空,但我相信他们会喜欢它,imho。:)
  5. 我认为你在回复中得到的信息也与Signature元素有关。我认为他们希望Signature元素有一些前缀(我猜是“ds”)。但在这里,我不确定100%。

    你知道,我正在和你一样战斗。我的消息安全时间戳有前缀“u”,他们不会抱怨它。虽然他们不喜欢binarysecuritytoken永远。:)我正在努力为IRS喜欢生成签名。 WCF非常隐秘,不允许在肥皂信封上轻松更改前缀或允许选择CanonicalizationMethod算法进行签名。

  6. 更新:能够成功向服务发送请求。马上告诉你:前缀不重要。重要的是:CorrectedInd标签必须出现在Form1095BUpstreamDetail中,属性recordType =“String”lineNum =“0”也必须存在。

    <强> UPDATE2 : 我改变的另一件事是我在ManifestDtl之前放置了ACABusinessHeader。 以下是我的设置:我使用WCF作为载体和SignedXml来生成签名。此外,我使用自定义gZip编码器(显而易见的原因0和自定义MtomEncoder读取服务响应(是的,是的,它是MTOMed :))你能相信那些pokemons吗?!?!?)并不是全部:它们发送响应作为多部分文档只有一部分!:))我不得不调整我的编码器来处理它。而且,服务开始表现得很好。希望它可能有所帮助。

    <强> 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 endpoit的绑定更改为“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. 4.2。修改方法WriteMessage(消息消息,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部分:

      5. 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));
          
        2. 用这个:

          item.GetHeader(Builder);
          

          那应该是它!开始你的鞋子,挖掘蓝调!:)))。

答案 1 :(得分:3)

首先,快速免责声明。这个答案是由fatherOfWine,Russ和Bon在这个和其他SO问题上提供的伟大的东西成为可能的。我真正做的就是将他们中的一堆东西结合起来,并解决我仍然遇到的问题,直到它起作用。更重要的是,这里提供的代码是 BAD ,可能不应该按原样使用。我计划清理这一点,因为我知道什么有用,我建议任何人都使用它来做同样的事情。一个很大的事情可能会跳到任何看到这个的人身上的是过多的静态变量,我用它来快速解决所有问题。说真的,不要在生产中使用它,这是几个小时的产品,只是把东西丢在墙上直到出现问题,但它应该提供一个很好的起点来获得更好的事情。

这里有太多的代码要真正包含它,所以我只是通过一些重点和一般发现然后包含VS解决方案的链接。

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

    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;
    
            }
        }
    }
    
  8. 84,只需要提供您自己提供的所有数据(包括所有收款人和付款人记录的完整附件文件,这不在此范围内,但应该很容易生成)。另请注意,这只是提交表单,而不是状态检查。当我开始工作时,我会尝试记住返回并更新这个答案(但是如果其他人已经拥有它并且想要分享,那么它也是非常好的。)

    编辑状态服务

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

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

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

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

答案 2 :(得分: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;
            }
        }
    }

答案 3 :(得分:1)

添加ds前缀实际上就是打破这个问题。 SignatureValue元素包含序列化SignedInfo元素的x509散列(这是具有一致空白的地方)。

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

只需删除对SignedInfo元素的修改,一切都应该是好的。它对我有用。

答案 4 :(得分:0)

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

除了jstill对状态“Reference.cs文件所做的更改之外,我还必须包含他对提交的BulkExchangeFileType文件所做的IncludeFileTypeReference.cs次更新为了使Deserializer方法能够 部分

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

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

<小时/> 状态'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));
        }
    }
}

答案 5 :(得分:0)

对于遇到以下错误的人:

  

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

美国国税局方面似乎存在一个问题,即他们期望的规模(根据文件)和他们实际接受的规模。最初,我有以下代码:

// 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个字节。我认为这是因为检索文件的大小会增加一些不属于实际内容的其他文件相关信息。

我已将有关其文档的问题通知美国国税局。