首页 > 开发 > .Net > 正文

.net实践:RSClientPrint打印本地报表

2023-04-27 19:28:50
字体:
来源:转载
供稿:网友

一个项目使用ReportViewer来呈现本地RDLC模块的报表,需要用户点击至少三次才能直正打印,用户感觉易用性很不好,需要我们修改。

  直接使用ACTIVEX控件RSClientPrint直接打印使用SQLSERVER报表服务的资料很多,也说的比较详细,可唯独没打印本地报表的相关内容,看来只能自已摸索了。

  经过研究有关打印SQLSERVER报表服务的资料,特别是这篇文章:http://www.codeproject.com/KB/reporting-services/RsClientPrint.aspx,决下先写一个简单的HTML文 件测试一下:代码

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
</head>
<BODY onload="Print()">
                <OBJECT ID="RSClientPrint"
classid="CLSID:5554DCB0-700B-498D-9B58-4E40E5814405" CODEBASE="/RSClientPrint-x86.cab" VIEWASTEXT></OBJECT>
                <script type="text/javascript" language="javascript">
                    function Print(oid,name) {
                        
if (typeof RSClientPrint.Print == "undefined") {
                            alert(
"Unable to load client print control.");
                            
return;
                        }
                        RSClientPrint.MarginLeft
= 0;
                        RSClientPrint.MarginTop
= 0;
                        RSClientPrint.MarginRight
= 0;
                        RSClientPrint.MarginBottom
= 0;
                        RSClientPrint.PageHeight
= 296.926;
                        RSClientPrint.PageWidth
= 210.058;

                        RSClientPrint.Culture
= 2052;
                        RSClientPrint.UICulture
= 2052;
                        RSClientPrint.UseSingleRequest
= true;
                        RSClientPrint.UseEmfPlus
= true;
                        
                        RSClientPrint.Print(
"http://localhost:2940/JDCJY/ReportHandler.ashx", "oid="+escape(oid)+"&name="+escape(name), "test");
                    }
                
</script>



                



                
</BODY>
</html>

  然后实现ReportHandler.ashx

  代码

public class ReportHandler : IHttpHandler

  {

  
public void ProcessRequest(HttpContext context)

  {

  Warning[] warningArray;

  HttpResponse response
= context.Response;

  response.StatusCode
= 200;

  MemoryStream lastMemoryStream
= null;

  context.Response.BufferOutput
= false;

  context.Response.ContentType
= null;

  context.Response.Expires
= -1;

  var ds
= new DataSet();

  LocalReport localReport
= new LocalReport();

  localReport.ReportEmbeddedResource
= string.Format("{0}.rdlc", context.Request.QueryString["name"]);

  localReport.DataSources.Add(
new Microsoft.Reporting.WebForms.ReportDataSource("ds", ds));

  StringBuilder builder
= new StringBuilder("");

  NameValueCollection requestParameters
= context.Request.QueryString ;

  
for (int i = 0; i < requestParameters.Count; i++)

  {

  
if (requestParameters.Keys[i] != null)

  {

  
if (requestParameters.Keys[i].StartsWith("rc:", StringComparison.OrdinalIgnoreCase))

  {

  builder.AppendFormat(
"<{0}>{1}", XmlConvert.EncodeName(requestParameters.Keys[i].Substring(3)), HttpUtility.HtmlEncode(requestParameters[i]));

  }

  }

  }

  builder.Append(
"");

  localReport.Render(
"IMAGE", builder.ToString(), delegate(string name, string extension, Encoding encoding, string mimeType, bool willSeek)

  {

  
if (!HttpContext.Current.Response.IsClientConnected)

  {

  
throw new HttpException("Client disconnected");

  }

  
if (lastMemoryStream != null)

  {

  this.SendPrintStream(lastMemoryStream, response);

  lastMemoryStream.Dispose();

  lastMemoryStream
= null;

  }

  lastMemoryStream
= new MemoryStream();

  
return lastMemoryStream;

  }, out warningArray);

  this.SendPrintStream(lastMemoryStream, response);

  lastMemoryStream.Dispose();

  this.SendPrintStream(null, response);

  
if (!response.BufferOutput)

  {

  
string a = context.Request.ServerVariables["SERVER_PROTOCOL"];

  
if (string.Equals(a, "HTTP/1.0", StringComparison.OrdinalIgnoreCase))

  {

  context.Response.Close();

  }

  }

  }

  
private void SendPrintStream(Stream stream, HttpResponse response)

  {

  
int length = 0;

  
if (stream != null)

  {

  length
= (int)stream.Length;

  }

  foreach (
byte num2 in BitConverter.GetBytes(length))

  {

  response.OutputStream.WriteByte(num2);

  }

  
if (stream != null)

  {

  stream.Position
= 0L;

  StreamToResponse(stream, response);

  response.Flush();

  }

  }

  internal
static void StreamToResponse(Stream data, HttpResponse response)

  {

  
int count = 0;

  
byte[] buffer = new byte[0x14000];

  
while ((count = data.Read(buffer, 0, 0x14000)) > 0)

  {

  response.OutputStream.Write(buffer,
0, count);

  }

  }

  
public bool IsReusable

  {

  
get

  {

  
return true;

  }

  }

  }

 

  再后经测试,直接加载上面的HTML页面就会提示直接打印。整个过程花了不少时间,有几个地方需要注意:

  1.在服务器端生成DEVICEINFO时一定要使用上面所示的方法,我在测试过程中为了图简单,直接使用我原来在WINFORM写的一个代码,固定的DEVICEINFO信息,结果打印出来时始终会重复,不知道是怎么回事,经过使用Reflector反编译Microsoft.ReportViewer.WebForms,仔细这里面实现的报表相关服务,发现这点实现的区别,才最终搞定问题

  2.服务器代码生成EMF流如果有问题,客户端会报一个错误代码,这时你很可能会以为是客户端的错误,我开始就是,因为报错误的速度太快了。我上网对对应问题代码的资料也没有明确结果,最后看还是直接跟踪代码试试,发现是服务器端代码有些问题。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表