c# - 从WCF应用程序传递回WPF应用程序的ReportServer的byte []反序列化上没有BinaryHeader错误

标签 c# wcf deserialization reportviewer reportserver

我将提供有关该项目的尽可能多的信息,然后提供相关的源代码,然后提供有关我已经尝试过的内容的信息(如果有,我将尝试包含我所尝试的内容的代码段)他们错了)。

我可以肯定我的问题与报表服务器返回的数据的序列化/反序列化有关,但是我将承认我完全有可能对此表示错误。

我有两个单独的项目(在Visual Studio 2013中)。 “客户端”项目是WPF应用程序,正在尝试使用ReportViewer显示ServerReport的内容。 “服务”项目是WCF应用程序,在调用Microsoft的ReportServer之后,它试图将报告的内容返回给客户端项目。该软件的先前版本具有客户端软件,该客户端软件直接向报表服务器发出请求。我所做的更改是将请求的参数发送到服务项目,该服务项目从我们的数据库中获取身份验证信息,并调用报表服务器。目的是我们的应用程序的客户端不应仅对数据知道或访问身份验证信息。

我对实现这一目标的任何解决方案持开放态度,即使它与我到目前为止所设定的完全不同。

该应用程序从当前用户的数据中填充可用报告的列表。单击“查看”按钮后,应使用报告查看器显示报告的详细信息。

在视图按钮的click事件中,将在调用RefreshReport()之前填充报表服务器请求的参数。该代码未更改,不受新过程的影响。

public partial class CurrentReport : (Our base page object)
{
  public ReportViewer _report;
  private string _reportPath;

  public CurrentReport()
  {
    try
    {
      InitializeComponent();
      _report = new ReportViewer();
      BuildReportViewer();
    }
    catch (Exception ex)
    {
      // Log Exception
    }
  }

  public void BuildReportViewer()
  {
    try
    {
      // wfh is an WindowsFormsHost property which
      //   CurrentReport inherits from its parent
      if (wfh.Child == null)
      {
        _report = new ReportViewer();
        wfh.Child = _report;
    }
    catch (Exception ex)
    {
      // Log Exception
    }
  }

  public bool RefreshReport(string reportPath, List<ReportParameter> parameters = null)
  {
    try
    {
      if ((parameters != null) && (!String.IsNullOrEmpty(reportPath)))
      {
        // Parameters passed to this method are of the type
        //   Microsoft.Reporting.WinForms.ReportParameter
        // Parameters the cloud service is expecting are of the type
        //   Microsoft.Reporting.WebForms.ReportParameter
        // The parameters accepted by the method are mapped to a list
        //   of parameters of web forms type before being added to
        //   the data transfer object
        List<CloudService.Service.ReportParameter> cloudParameters = new List<CloudService.RTRService.ReportParameter>();

        if (parameters.Count > 0)
        {
          foreach (ReportParameter rp in parameters)
          {
            List<object> cloudValues = new List<object>();

            foreach (string s in rp.Values)
              cloudValues.Add(s);

            cloudParameters.Add(new CloudService.Service.ReportParameter { m_name = rp.Name, m_value = cloudValues, m_visible = rp.Visible });
          }
        }

        CloudService.Service.ReportDTO rdto = new CloudService.Service.ReportDTO();
        rdto.reportParameters = cloudParameters;
        rdto.reportPath = reportPath;
        rdto.reportProcessingMode = CloudService.Service.ProcessingMode.Remote;

        ServiceRequests.ServiceRequests.service = new ServiceRequests.ServiceRequests(MyApp.Authentication);
        MemoryStream stream = service.Report(rdto);
        DataTable reportData = new DataTable { TableName = "Report" };
        BinaryFormatter formatter = new BinaryFormatter();
        reportData = (DataTable)formatter.Deserialize(stream);
        _report.LocalReport.DataSources.Add(new ReportDataSource("Report", reportData));
        _reportPath = reportPath;
        _report.RefreshReport(); 
      }
      // The code making the call to this method is checking for an error
      return false;
    }
    catch (Exception ex)
    {
      // Log Exception
    }
  }


服务请求service.Report(ReportDTO)在用于服务请求的单独文件中

public MemoryStream Report(ReportDTO rdto)
{
  ServiceClient service = null;

  try
  {
    service = new ServiceClient();
    service.InnerChannel.OperationTimeout = new TimeSpan(0,5,0);
    service.Open();

    ReportDTORequest request = new ReportDTORequest();
    request.Authentication = _authentication; // global property
    request.Entities = new List<ReportDTO>();
    request.Entities.Add(rdto);

    return service.Report(request).Entities.FirstOrDefault();
  }
  catch (Exception ex)
  {
    throw ex;
  }
  finally
  {
    if (service != null)
    {
      service.Close();
    }
  }
}


该请求由云项目中的运营合同接收。

[WebInvoke(Method = "POST")]
[OperationContract]
public Response<MemoryStream> Report(Request<ReportDTO> request)
{
  Response<MemoryStream> response = new Response<MemoryStream>();
  response.Status = ResponseStatus.FAILED;

  try
  {
    if ((request != null) && (request.Entities != null))
    {
      if (request.Authentication != null)
      {
        // I know this part is unusual but it is working around a complication between an old custom response object and a new custom response object to replace the old one, which is still being used elsewhere
        KeyValuePair<ResponseStatus, string> kvp = request.Authentication.Authenticate(_globalAuthenticationToken);
        response.Status = kvp.Key;
        response.Messages.Add(kvp.Value);

        if (response.Status == ResponseStatus.SUCCESS)
        {
          ReportDTO rdto = request.Entities.FirstOrDefault();

          if ((rdto != null) && (!String.IsNullOrEmpty(rdto.reportPath)))
          {
            // Get settings from database and populate in string variables username, password, domain, and uri

            Microsoft.Reporting.WebForms.ReportViewer rv = new Microsoft.Reporting.WebForms.ReportViewer();

            rv.ServerReport.ReportPath = rdto.reportPath;
            rv.ServerReport.ReportServerUrl = new Uri(uri);
            rv.ServerReport.ReportServerCredentials = new CustomReportCredentials(username, password, domain);

            rv.ServerReport.Refresh();

            if ((rdto.reportParameters != null) && (rdto.reportParameters.Count > 0))
            {
              rv.ServerReport.SetParameters(rdto.reportParameters);
            }

            string mimeType;
            string encoding;
            string extension;
            string[] streamIDs;
            Microsoft.Reporting.WebForms.Warning[] warnings;

            byte[] bytes = rv.ServerReport.Render("Excel", null, out mimeType, out encoding, out extension, out streamIDs, out warnings);

            if ((bytes != null) && (bytes.Count() > 0))
            {
              BinaryFormatter formatter = new BinaryFormatter();
              MemoryStream stream = new MemoryStream();
              formatter.Serialize(stream, bytes);
              response.Entites.Add(stream);
              stream.Close();
              response.Status = ResponseStatus.SUCCESS;
            }
            else
            {
              response.Messages.Add("Unable to render server report");
              foreach (Microsoft.Reporting.WebForms.Warning warning in warnings)
              {
                response.Messages.Add(warning.ToString());
              }
              response.Status = ResponseStatus.FAILED;
            }
          }
          else
          {
            response.Messages.Add("Invalid request data");
            response.Status = ResponseStatus.FAILED;
          }
        }
      }
      else
      {
        response.Messages.Add("Unable to authenticate user request");
        response.Status = ResponseStatus.FAILED;
      }
    }
    else
    {
      response.Messages.Add("Invalid request object");
      response.Status = ResponseStatus.FAILED;
    }
  }
  catch (Exception ex)
  {
    // Log Exception
  }
  return response;
}


根据GotReportViewer,可以将DataTable设置为ReportViewer.LocalReport的数据源,因此我一直在尝试将此字节数组返回到我的客户端项目,并将其转换为DataTable格式以显示在ReportViewer中。

虽然我无法查看从调用ReportServer回来的实际数据,但我知道我正在测试的报告没有损坏,因为在该项目的旧版本中可以很好地加载它们。此外,从对ServerReport.Render的调用返回的字节数组的大小略超过98k字节,因此我假设报告已从ReportServer正确返回到我的云项目。这就是为什么我可以确定我的问题在于序列化/反序列化的原因。

当控件返回到客户端项目时,在reportData = (DataTable)formatter.Deserialize(stream);行出现了我遇到的错误。

引发的错误是Binary stream '0' does not contain a valid BinaryHeader

我在StackOverflow上发现了许多与此二进制标头错误有关的问题,但这些问题要么与我的具体情况无关,要么以它是数据问题为假设而结束,我非常愿意这样做。声称不是。

我发现有关从wcf应用程序向报表服务器发出请求的大多数问题基本上都说这很困难,并且提供了一些替代方法,但是我找不到任何方法可以解决我遇到的问题,或者可以解决的方法我所遇到的问题,或者避免使WPF应用程序访问身份验证信息。

到目前为止,我已经尝试过:


只需rv.ServerReport.Render("Excel");即可拨打电话
直接将byte []返回到客户端项目,而不是作为MemoryStream返回
转换为数据表时可能还有其他几种变化(这已经花了很长时间了,我不记得我尝试过的所有方法)


我一直找不到直接将rv.ServerReport.Render结果转换为DataTable的方式。

请让我知道更多(或只是不同的)信息会有所帮助。

最佳答案

我认为Excel文件正在生成错误数据或垃圾数据。您会分享Excel内容吗

关于c# - 从WCF应用程序传递回WPF应用程序的ReportServer的byte []反序列化上没有BinaryHeader错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44762984/

相关文章:

c# - 数据契约(Contract)问题

生产中的 WCF "Too many active security negotiations"错误

java - 导入和反序列化时对象显示 null

c# - 如何在缓存中存储数据?

c# - 获取 WCF 服务的当前端点?

.net - wsHTTPBinding 身份验证错误

java - 使用 Gson 反序列化 JSON 时引用父对象

java - 反序列化多态 JSON 字符串

c# - FlexLayout 可绑定(bind)源 -xamarin 表单 - 如何在不绑定(bind)的情况下获取数据

c# - 如何检查枚举是否包含数字?