[转载]操作PDF文档功能的相关开源项目探索iTextSharp 和PDFBox

mikel阅读(1238)

[转载]操作PDF文档功能的相关开源项目探索——iTextSharp 和PDFBox – 无痕客 – 博客园.

很久没自己写写心得日志与大家分享了,一方面是自己有点忙,一方面是自己有点懒,没有及时总结。因为实践是经验的来源,总结是提升的基础,所以 无论怎样,自己都该反省一下。今天我主要是研究学习了两个PDF文档的相关类,iTextSharp 和PDFBox。我研究出发点是实现PDF文档的检索,需要提取PDF文档中的文字内容,然后通过正则匹配实现搜索。

类似 Windows Search的文件搜索系统》中介绍的文件检索方法是很不错的,但它里面对PDF中的中文检索不支 持,因为里面调用的iTextSharp不能很好地支持英文,PdfReader类的GetPageContent()方法无法正常返回中文字符,经我测 试,并非简单的编码问题。所以,急需能够从PDF中提取text功能。

我首先学习iTextSharp.dll 下载:http://sourceforge.net/projects/itextsharp/ 这里面有很多输出PDF文档的简单例子(下载iTextSharp例子),在学习中发现,不支持中文内容输出。在网上搜索相关内容发现,原来是缺少字体库。 有两种方法解决:

1.自己指定系统的字体库,创建PDF中使用的字体。参见:http://unruledboy.cnblogs.com/Skins/ChinaHeart/Controls/archive/2005/08/30/225984.html

Document document = new Document(PageSize.A4,50, 50, 50, 50);
try
{
PdfWriter writer = PdfWriter.GetInstance(document, new FileStream(“Chap11.pdf”, FileMode.Create));

//下面是创建PDF文档加密的
//writer.SetEncryption(PdfWriter.STRENGTH40BITS,”654321″, “654321”, PdfWriter.AllowCopy);
document.Open();

//指定字体库,并创建字体
BaseFont baseFont = BaseFont.CreateFont(
“C:\\WINDOWS\\FONTS\\SIMHEI.TTF”,
BaseFont.IDENTITY_H,
BaseFont.NOT_EMBEDDED);
iTextSharp.text.Font font = new iTextSharp.text.Font(baseFont, 9);

//指定输出内容的字体

document.Add(new Paragraph(” This document is Top Secret! “, font));
document.Close();
}
catch (Exception de)
{
Console.WriteLine(de.StackTrace);
}

2.从http://sourceforge.net/projects/itextsharp/ 下载扩展字体库 iTextAsianCmaps.dll 和iTextAsian.dll,支持亚洲字体。

下载界面如下:

/// <summary>
/// 创建中文字体(实现中文)
/// </summary>
/// <returns></returns>
public static iTextSharp.text.Font CreateChineseFont()
{
BaseFont.AddToResourceSearch(“iTextAsian.dll”);
BaseFont.AddToResourceSearch(“iTextAsianCmaps.dll”); //”STSong-Light”, “UniGB-UCS2-H”,
BaseFont baseFT=BaseFont.CreateFont(“STSong-Light”, “UniGB-UCS2-H”, BaseFont.EMBEDDED);

iTextSharp.text.Font font = new iTextSharp.text.Font(baseFT);
return font;
}

“UniGB-UCS2-H” “UniGB-UCS2-V”是简体中文。 “STSong-Light”是字体名称。BaseFont.EMBEDDED是将字体嵌入文档内。

其次,我接下来尝试在使用iTextSharp读对象类时,指定字体库,可是很遗憾没有相应方法。请参照:http://www.cnblogs.com/diction/articles/1120984.html (提 取文本不支持中文)而且,即使有也很不灵活,因为你不可能预知PDF文档中使用的字体,PDF文档中可能有多种字体。后来,搜索网页相关信息发现:原来iTextSharp的操作PDF文档优势是PDF文档的创建。

需求是学习和工作的动力

我的原始目标是找到PDF文档内容提取为文本的方法,我转向《How to parse PDF files》 该文章完整讲述了PDF文档提取文本的方法和整个解决过程 思路,我会单独转载该文章,希望不能访问国外网的网友也能看到。PDFBox的下载http://sourceforge.net/projects/pdfbox/files/ 下 载解压后里面内容很丰富,

所有需要的dll都包含在Bin文件夹里面

“PDFBox is a Java PDF Library. This project will allow access to all of the components in a PDF document. More PDF manipulation features will be added as the project matures. This ships with a utility to take a PDF document and output a text file. ”

PDFBox是个JAVA开源项目,里面使用IKVM.NET开源项目http://www.ikvm.net/ 支持JAVA类库在.NET中调用。

IKVM.NET is an implementation of Java for Mono and the Microsoft .NET Framework. It includes the following components:

  • A Java Virtual Machine implemented in .NET
  • A .NET implementation of the Java class libraries
  • Tools that enable Java and .NET interoperability

对IKVM.NET的学习,对以后在.NET下使用JAVA类库很有帮助,其实IKVM.Runtime.dll 就是封装了JAVA类库的运行环境。

需要添加的DLL有:FontBox-0.1.0-dev.dll、IKVM.GNU.Classpath.dll、 IKVM.Runtime.dll、PDFBox-0.7.3.dll

PDFBox使用实例代码如下:请参照:http://www.cnblogs.com/wuhenke/archive/2010/04/16/1713949.html

private static string parseUsingPDFBox(string filename)
{
PDDocument doc = PDDocument.load(filename);

PDFTextStripper stripper = new PDFTextStripper();

return stripper.getText(doc);
}

PDFBox功能很强大,有时间值得好好学习一下。

参考:

http://www.codeproject.com/kb/cpp/ExtractPDFText.aspx?df=100&forumid=47947

http://www.codeproject.com/KB/string/pdf2text.aspx

http://www.cnblogs.com/hardrock/

http://www.ikvm.net/

[转载]MVP模式在asp.net中的应用

mikel阅读(1037)

[转载]MVP模式在asp.net中的应用 – 奋斗的天空 – 博客园.

前段时间,由于项目中需要用到MVP模式,于是我便来博客园查了一下,发现博客园有关MVP模式的资料少之又少,加上本人在博客园潜水这么久, 也想出来透透气啦,从而产生了写博的冲动。整个项目做下来,也对MVP模式有了一定的了解,特写下这篇文章来做一个总结吧,希望对学习MVP模式的朋友有 所帮助。话不多说,直接上图:

但是本章的重点不是这张图,而是在ASP.NET项目中怎么去用MVP模式。如果您对MVP模式有所了解的话,那么接下来就要上菜啦。

下面就用一个view开始:

public interface IMvpView { }

这是一个最基本的View接口,也就是说我们的UI(page,control)会直接或间接的继承它,我们还可以在这个接口里定义一些属性和 方法,而这些属性和方法是在我们每个界面都会用到的。很简单吧!

接下来就是一个presenter的基础类:

public abstract class Presenter<TView> where TView : IMvpView { public TView View { get; set; } public virtual void OnViewInitialized() { } public virtual void Save() { } }

这是一个最基本的presenter class,我把它定义为一个抽象的范型类。这个类的内容也很简单,它有一个TView类型的View属性,注意这里的TView不应该是一个具体 View,而应该是一个View的抽象。它还包括两方法,OnViewInitialized()和Save(), 我都把它们定义为Virtual,是要在继承类中重载。其中OnViewInitialized()方法里主要执行一些当 (IsPostBack==false)的操作,当然你还可以增加一个OnViewLoad()方法,来执行当页面加载时的操作.

定义了一些最基本的,接下来我要定义一些东东继承它们。

接下来创建一个IPersonView,它继承自我们最基本的view接口IMvpView:

public interace IPersonView:IMvpView { IList<Person> Persons{get;set;}
void Save(); }

接下来我又创建了一个PersonPresenter类,它继承自Presenter抽象类

public class PersonPresenter : Presenter<IPersonView> { private readonly IPersonController _controller; public PersonPresenter(IPersonController controller) { _controller = controller; } public override void OnViewInitialized() { View.Persons= _controller.GetPersons(); } public override void Save() { //do something } }

等等,怎么会突然冒出个IPersonController,这个接口干嘛的?重点来啦,presenter凭什么可以承担起UI的所有逻辑, 就是因为有这个IPersonController接口,这个接口的主要职责是通过您的Data Layer获得presenter完成UI逻辑所需要的数据,它是presenter的强大靠山。在这个例子中,IPersonController获得 person列表,来给赋给View的Persons属性,当然还做一些保存的动作(Save()).

接下来我还要做一件很有意义的事情,就是创建一个抽象的基础页面类:

public abstract class ViewBasePage<TPresenter, TView> : Page,IMvpView where TPresenter : Presenter<TView> where TView : IMvpView { protected TPresenter _presenter; public TPresenter Presenter { set { _presenter = value; _presenter.View = (IMvpView)(object)this; } } }

所有UI都会继承这个类,虽然它现在所做的事情很简单(仅仅是做范例),当然你还可以加一些在其它界面都会用到的方法或者属性来增强这个基类。

在这个例子中,我没有去实现Data Layer和controller,当然这也不是本文的重点,我希望通过这篇文章,让学习MVP模式的朋友,能对MVP模式有一个新的认识。

[原创]百度排名日志分析

mikel阅读(1252)

LogParser的导入SQL Server的命令:

logparser -i:IISW3C "SELECT TO_LOCALTIME(TO_TIMESTAMP([date], [time])) as [logdate] , [s-sitename], [s-computername], [s-ip], [cs-method], [cs-uri-stem], [cs-uri-query], [s-port], [cs-username], [c-ip], [cs-version], [cs(User-Agent)], [cs(Cookie)], [cs(Referer)], [cs-host], [sc-status],[sc-substatus], [sc-win32-status], [sc-bytes], [cs-bytes], [time-taken] INTO IISLog FROM d:\logs\ex*.log WHERE TO_LOWERCASE (EXTRACT_EXTENSION(cs-uri-stem)) NOT IN (‘gif’;’jpg’;’png’;’bmp’;’ico’;’axd’)" -o:SQL -server:MIKEL\MIKEL -database:Logs -driver:"SQL Server" -username:sa -password:justdoit -createTable:OFF

Dos下通过Ping反查IP指向的域名命令如下:
ping -a 123.125.66.134

百度蜘蛛标示如下:

百度各个产品使用不同的user-agent:

产品名称 对应user-agent
无线搜索 Baiduspider-mobile
图片搜索 Baiduspider-image
视频搜索 Baiduspider-video
新闻搜索 Baiduspider-news
百度搜藏 Baiduspider-favo
百度联盟 Baiduspider-cpro
网页以及其他搜索 Baiduspider

1.视频\图片信息蜘蛛抓取IP段:61.135.168.44-61.135.168.50

2.js脚本抓取蜘蛛IP段:61.135.165.202-61.135.165.206

[转载]解决下载/上传大文件问题(IIS6)

mikel阅读(1066)

[转载]解决下载/上传大文件问题(IIS6).

Windows 2003,当在IIS6上下载(/上传)大文件时,

会出现错误(log 文件中):80004005 Response_Buffer_Limit_Exceeded。

原因:IIS6 有一个缺省的设置:AspBufferingLimit= 4194304 是4M。

解决办法:将AspBufferingLimit的值增大到合适的大小。

步骤:
1. 修改IIS设置,允许直接编辑配置数据库

管理工具->IIS管理器里,选择计算机,右键,选择属性,然后选中“Enable Direct Metabase Edit”.
2. 修改IIS配置文件

1). 先在服务管理器里关闭iis admin service服务

管理工具->服务->iis admin service->停止。

2). 用文本编辑器打开C:\Windows\System32\Inesrv\下的Metabase.xml文件 注意:修改文件之前请先      备份。

3). 修改对下载文件大小限制
找到AspBufferingLimit,把它修改为你所需的大小。
例如:AspBufferingLimit=”8388608″ (8M)
修改对上传文件大小限制
找到ASPMaxRequestEntityAllowed 把他修改为需要的值,默认为204800,即200K 把它修改为你所       需的大小。如:8388608(8M)
例如:AspRequestQueueMax=”8388608″

4). 然后开启www服务
管理工具->服务->World Wide Web Publishing Service->开启

备注:
也可以直接在控制台命令行运行 ADSUTIL.VBS更改此值。不用停止IIS。
例如改为8M:运行 “ADSUTIL.VBS SET W3SVC/AspBufferingLimit 8388608” 另外,可以在控制台命令行直接停止和启动IIS。

停止:“Net stop iisadmin /y”

启动:“Net start w3svc”

也可以使用IIS6 Resource Kit中的Metabase Explorer (MBExplorer.exe)(代替Metaedit 2.2)编辑。

IIS6 Resource Kit的下载地址:
http://support.microsoft.com/kb/840671
http://www.microsoft.com/downloads/details.aspx?FamilyID=56fc92ee-a71a-4c73-b628-ade629c89499&DisplayLang=en

IIS6命令行工具的说明:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/iissdk/html/5e7f8cde-4a01-42bd-acaf-f8f7d091ef7c.asp

[转载]升级到NVelocity1.1版本

mikel阅读(1126)

[转载]升级到NVelocity1.1版本 – 小草 – 博客园.

由于NVelocity项目太久没有升级了,虽然看到Velocity经常发布一些新的功能,但.net版本的修改似乎比较迟。以至于很少关注升级情况。由于前期使用这个模板引擎的时候发现对DataTable支持不太好,原先想自己修改一下源代码,但分析了一下源代码发现改不动,也没有精力去研究。(最 近越来越懒了^_^

今天看到Richie写的关于1.1的两篇文章发现新版本已经解决了我想要的 支持。真是太高兴了,随即结合《Castle NVelocity – 1.1整 理了一下相关的代码供大家参考。

原先使用0.4X版本的时候其实也可以使用DataTable,但就是有些麻烦,我也是经过反复的测试后终于想到一个办法来处理,作法如下:需要循环行记录的情 况下再循环列,然后根据列号把值写到变量里,相当的麻烦。

#foreach($Item in $dtSubSortList.Rows)

#set ($rownum = 0)

#foreach($value in $Item.ItemArray)

#set ($rownum = $rownum+1)

#if($rownum == 1)

#set($CATEGORY_ID = “$value”)

#end

#if($rownum == 2)

#set($CATEGORY_NAME = “$value”)

#end

#end

<tr> <td class=”daoh_1″><div class=”wenz_2″><a href=”$!{WebRoot}cms/listPage.aspx?categoryId=$!{CATEGORY_ID}&parent=$!{categoryid}”>$CATEGORY_NAME</a></div></td></tr>

#end

新版本的写法就非常的简单了:

#foreach($Item in $dtSubSortList.Rows)

<tr> <td class=”daoh_1″><div class=”wenz_2″><a href=”$!{WebRoot}cms/listPage.aspx?categoryId=$Item.CATEGORY_ID”>$Item.CATEGORY_NAME</a></div></td></tr>

#end

但现在不足的 之处就是还不支持索引的写法,如$Item[0] 或者 $Item[“字段名“]

我整理的部分代码里封装了 NVelocityHelper,并写一下模板页的基类PageBaseTemplate等内容,仅供大家参考。

PageBase.cs

这个属性可以通过一些扩展实现多级子站的模 板定制功能(大家可以自己思考一下,我只是使用了目录的方式进行处理,应该还有其它更好的方法)。

1.1版本的 使用说明在《Castle NVelocity – 1.1 》有详细的说明,非常感谢。

原代码及最新的组件都在这里: /Files/liubiqu/NVelocity1.1Demo.rar

代码内容:

由于时间关系还没有详细的研究,下列问题有待进一步测试:

1、 velocity.GetTemplate是否有提供一些缓存与优化的处理

2、 velocity.Evaluate的时候log的参数有什么用处及整 合到其它日志方法

3、在性能方 面有没有更好的处理方式。

[原创]ASP.NET MVC链接地址的中文信息编码

mikel阅读(744)


<%="/Systems/DealerSaleList?isNew=1&fromDate=" + this.dealerCondition.ShopName + "&finishDate=" + this.dealerCondition.Service+"&dealerName=" + System.Web.HttpUtility.UrlEncode(ds.DealerName, System.Text.Encoding.GetEncoding("UTF-8")) %>

[转载].NET基础 - 简单几句说说GC(垃圾回收器)

mikel阅读(889)

[转载].NET基础 – 简单几句说说GC(垃圾回收器) – 今天你开心么,朋友? – 博客园.

.NETFramework包含两大部分,其一为BCL(基础类库),其二为CLR(公共语言运行库),这里要说的正是CLR中的GCGarbage Collector),俗称垃圾 回收器。

我们不如先用正规的方法描述一下垃圾回收中的几个要点:

1 CLR创建对象时,发现CLR所控制的堆中的内存不足以创建该对象,触发GC进行垃圾收集。

2 等待当前所有.NET应用程序处于挂起状态下,才真正开始收集动作,并非马上执行,也没有办法立即执行!

3 为共享堆中所有被引用的对象建立白名单,同时将所有带有析构标志位的对象统一放置到FReachable红名单中(先要折磨一下再释放)。

4 开始释放,具体的形式呢就是把白名单中的对象统一移动到堆的底部,其他没有点到名的,就会被释 放掉啦,同时将堆指针更新到可用对象最高的那个位置。

5 现在来处理红名单中的哥几个,GC先执行这些对象中的析构函数,同时重置析构标志为已处理,然后等待他们的就是下一次的清理,在那之前这些哥们还都 在堆里。

下面再对上面的几个步骤做一下说明:

1 为对象创建析构函数的目的是为了释放掉非托管资源(即GC管不到的CLR外的,可以理解为OS资源),当然,我们也可以通过编写Dispose()方法来手动释放非托管资源,但不会释放掉堆中的资源。

2 不像C++中对析构函数的使用,.NET中应尽量少地使用析构函数,因为如果析构函数过多,我们必须至少调用两次GC回收,才能真正释放出资源。

3 我们可以通过编码为GC添加或减少内存压力,目的只有一个,就是借此来控制收集的时机。

4 充分考虑到GC收集的范围限制,在编写需要调用非托管资源的应用时,建议 提供Dispose()方法和析构函数两个手段,当然,我们可以通过使用公共代码的 方式,来保证两者的工作不会出现冲突。这样我们将获得灵活的处理能力。

5 同时,我们可以设定有关GC的一些操作特性,包括是否关闭多线程调用及是否对2代进行资源收集等等。

6 堆分为三代:012,其容量逐渐递增,但其活跃程度逐层递减,每次收集后,白名单中的哥们都会自动升级,很明显,级数越高,证明使用的时间 越长,越可能是全局的一些内容。

[转载]介绍一下我自己开发的全新Remoting技术。(本地调用远程代码)

mikel阅读(857)

[转载]介绍一下我自己开发的全新Remoting技术。(本地调用远程代码) – 美丽人生 – 博客园.

前言

——————

本文介绍了一种全新的调用远程代码的技术。参考了微软 的remoting、webservice。

基础知识

——————

先抛开具体的代码,如果要实现远程代码调用,一个最简 单的模型是:

1. 使用一个HttpHandler,当有请求的时候,调用对应的代码,返回。例如:

代码

class RemoteHandler : IHttpHandler, IReadOnlySessionState
{
public bool IsReusable
{
get
{
return true;
}
}

public void ProcessRequest(HttpContext context)
{
//这里创建实例RemotingGreeting

RemotingGreeting greeting
= new RemotingGreeting();


byte[] response = greeting.Helloworld();

//这里返回调用结果到客户端

context.Response.Clear();

context.Response.ContentType = application/octet-stream;

BinaryWriter writer = new BinaryWriter(context.Response.OutputStream);

writer.Write(response);

writer.Flush();

writer.Close();

context.Response.End();
}
}

2. 客户端使用Http去访问这个Handler,就实现了最原始的远程调用

这段代码,就实现了远程调用 RemotingGreeting这个类,获取方法Helloworld();的返回值。

那么,这个过程如何实现通用呢?如何实现框架化?首先 先看看实际代码的调用效果:

代码实例

——————

首先声明一个被远程调用的对象,RemotingGreeting. 以及一个接口IRemotingGreeing

代码

class RemotingGreeting : IRemotingGreeting
{
public string Greeting(string message)
{
return Hi! + message;
}
}

[Remote(Pixysoft.Framework.Remoting.Demo, Pixysoft.Framework.Remoting.Demo.RemotingGreeting)]//这里实际指定了接口具体实现的类的Assembly和Type
public interface IRemotingGreeting
{
string Greeting(string message);
}

然后本地实现远程调用:

代码

using System;
using System.Collections.Generic;
using System.Text;

namespace Pixysoft.Framework.Remoting.Demo
{
class testcase
{
public void test()
{
//指定了调用的入口点 url
string url = http://localhost:1300/Apis/remoting.asmx;

//创建本地调用的透明代理
IRemoteChannel<IRemotingGreeting> channel = RemotingManager.CreateRemoteChannel<IRemotingGreeting>(url);

//登录远程服务器
channel.Login(xxxxxx, xxxxxxxxx);

//远程调用
string greeting = channel.RemoteProxy.Greeting(pixysoft);

//登出
channel.Logout();

//打印结果,就是“Hi!pixysoft”
Console.WriteLine(greeting);
}
}
}

正文

——————

远程调用框架的思路是:

1. 本地创建一个透明代理(RealProxy.GetTransparentProxy())

2. 用户本地的请求,被透明代理序列化为XML

3. XML传递到服务器的Handler,被解析后,加载对应的对象(Spring? 动态加载)

4. Handler运行对象,获取返回值,再序列化为XML,返回本地。

5. 本地透明代理解析XML,获取返回值。

第一步,创建透明代理。请各位先阅读 一篇相关的文章:

http://www.cnblogs.com/zc22/archive/2010/02/22/1671557.html

这里贴出核心代码的一个例子:

代码

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Remoting.Proxies;
using System.Runtime.Remoting.Messaging;

namespace Pixysoft.Framework.TestDrivens
{
public class Mock<TInterface> : RealProxy
{
public Mock()
:
base(typeof(TInterface))
{
}

public TInterface Value
{
get
{
return (TInterface)this.GetTransparentProxy();
}
}

public override IMessage Invoke(IMessage msg)
{
IMethodCallMessage methodCall
= msg as IMethodCallMessage;

//我返回 int = 1

return new ReturnMessage(1, null, 0, null, methodCall);
}
}

public interface IMock
{
int Devide(int a, int b);
}

public class testrealproxy //测试代码在这 里!!!
{
public void test()
{
IMock mock
= new Mock<IMock>().Value;

Console.WriteLine(mock.Devide(1, 2));

//输出 = 1
}
}
}

这篇文章讲解了如何实现一个接口的透明代理。本质在

public override IMessage Invoke(IMessage msg)

这里,对用户调用的方法进行序列化操作。

第二步,调用的序列化。

上文透明代理通过以下代码获取了用户调用的方法反射

IMethodCallMessage methodCall = msg as IMethodCallMessage;

MethodInfo method = methodCall.MethodBase as MethodInfo;

这里,要对调用方法MethodInfo进行序列化。 当然,就是自己去建立一个MethodInfo的xml描述,例如:

代码

<method assembly=”Pixysoft.Framework.Remoting” type=”Pixysoft.Framework.Remoting.Core.RemotingHelloworld” method=”HelloWorld” parametercount=”4″>
<parameter type=”DateTime” parameter=”para1″>2010-4-12 下午 08:52:21</parameter>
<parameter type=”String” parameter=”para2″>2</parameter>
<parameter type=”Int32″ parameter=”para3″>12</parameter>
<parameter type=”IRemotingValue” parameter=”para4″ />
<return type=”IRemotingValue” />
</method>

这个是我实际建立的MethodInfo的xml描 述。如何建立就不说了吧,很简单,用StringBuilder去拼就行了。

第三步,httpHandler解析 XML,加载对象运行结果。

客户端通过HttpPost到服务端,服务端获取了 XML之后,只要根据对应的参数加载Assembly,然后获取对象即可。具体涉及到了一些反射的操作:

Assembly assembly = Assembly.LoadFrom(assemblyname);

Type type = assembly.GetType(typename);

MethodInfo method = type.GetMethod(methodname);

获取了MethodInfo之后,只要把参数放入,获 取返回值即可。

代码

//实例化一个对象

ConstructorInfo constructorInfo
=
type.GetConstructor(BindingFlags.Public
| BindingFlags.NonPublic | BindingFlags.Instance,
null, new Type[] { }, null);

object remoteObject = constructorInfo.Invoke(new object[] { });

//调用这个对象的方法 这里省略了如何获取parameters过程

object returnvalue = method.Invoke(remoteObject, parameters);

第四步 Handler序列化返回值 为XML,返回本地。

只要把returnvalue序列化为xml即可。具 体就不叙述了。

第五步 本地透明代理解析XML,获取返回值。

本地透明代理把序列化的returnvalue再反序 列化为对象即可,然后返回

return new ReturnMessage(returnvalue, null, 0, null, methodCall);

难点讲解

——————

1. 整个调用过程最难的地方在于序列化操作。因为微软不支持接口的序列化、不支持内部类的序列化。这里需要自己实现。

2. 其次最难的在于值类型的操作。因为值类型进入了RealProxy之后,全部被装箱成为了对象(object)。这个时候直接把对象返回会抛异常,因此需 要根据具体的method.ReturnType, 逐一用值类型解析返回。

3. 再次,就是动态加载问题。Assembly.LoadFrom会有很多问题,比如版本问题、路径问题。因此要实现一个事件

AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);

实现了这个event之后,能够代码指定搜索 assembly的位置。具体代码我就不列举了。

后记

——————

写代码的过程,和拼装模型是一样的。只要我们手上的零 件越来越多,能实现的功能和效果就越来越多!

[转载]Web打印的解决方案之普通报表打印

mikel阅读(1082)

[转载]Web打印的解决方案之普通报表打印 – wuhuacong(伍华聪)的专栏 – 博客园.

做过很多的Web项目,大多数在打印页面内容的时候,采用的都是通过JavaScript调用系统内置的打印方法进行打印,也就是调用 PrintControl.ExecWB(?,?)实现直接打印和打印预览功能。打印的效果及控制性虽然不是很好,但是也能勉强使用,应付一般的打印还是 可以的了。

代码如下所示:

代码

//调用PrintControl.ExecWB(?,?)实现直接打印和打印预览功能。(直接用系统提供的print()方法打印无法隐藏某些 区域)
//
preview:是否显示预览。null/false:不显示,true:显示
function printPage(preview)
{
try
{
var content=window.document.body.innerHTML;
var oricontent=content;
while(content.indexOf({$printhide})>=0) content=content.replace({$printhide},style=’display:none’);
if(content.indexOf(ID=\PrintControl\“”)<0) content=content+<OBJECT ID=\PrintControl\ WIDTH=0 HEIGHT=0 CLASSID=\CLSID:8856F961340A11D0A96B00C04FD705A2\></OBJECT>;
window.document.body.innerHTML
=content;
//PrintControl.ExecWB(7,1)打印预览,(1,1)打开,(4,1)另存为,(17,1)全选,(10,1)属性, (6,1)打印,(6,6)直接打印,(8,1)页面设置
if(preview==null||preview==false) PrintControl.ExecWB(6,1);
else PrintControl.ExecWB(7,1); //OLECMDID_PRINT=7; OLECMDEXECOPT_DONTPROMPTUSER=6/OLECMDEXECOPT_PROMPTUSER=1
window.document.body.innerHTML=oricontent;
}
catch(ex){ alert(执行JavaScript脚本出错。); }
}

function printConten(preview, html)
{
try
{
var content=html;
var oricontent=window.document.body.innerHTML;
while(content.indexOf({$printhide})>=0) content=content.replace({$printhide},style=’display:none’);
if(content.indexOf(ID=\PrintControl\“”)<0) content=content+<OBJECT ID=\PrintControl\ WIDTH=0 HEIGHT=0 CLASSID=\CLSID:8856F961340A11D0A96B00C04FD705A2\></OBJECT>;

window.document.body.innerHTML=content;
//PrintControl.ExecWB(7,1)打印预览,(1,1)打开,(4,1)另存为,(17,1)全选,(10,1)属性, (6,1)打印,(6,6)直接打印,(8,1)页面设置
if(preview==null||preview==false) PrintControl.ExecWB(6,1);
else PrintControl.ExecWB(7,1); //OLECMDID_PRINT=7; OLECMDEXECOPT_DONTPROMPTUSER=6/OLECMDEXECOPT_PROMPTUSER=1
window.document.body.innerHTML=oricontent;
}
catch(ex){ alert(执行Javascript脚本出错。); }
}

上面两个函数放在一个Js文件中,在页面内容中通过应用该脚本文件并调用进一步封装的函数即可打印指定部分的内容:

<script language=javascript>
function Print(preview) {
var text = document.getElementById(content).innerHTML;
printConten(preview, text);
}

打印的效果大致如下图所示,如果打印的页面在框架页面中,那么需要选定“仅打印选定框架”的选项。

采用此种方法,不需要安装任何控件,具有很好的兼容优势,不过出来的报表内容,好像控制起来会比较麻烦一些,特别对于一些报表方面的打印,需要输出 复杂的内容是,也有一定的缺陷,但总体来说,也是一个较好的选择。

后来在需要做一些证件套打方面的工作,这个控件就做不到了,因此需要一种方法或者控件,能够较好处理套打方面的事情。

无意间,发现一个比较好的打印控件,支持各种格式的打印,还有我关心的证件套打功能,功能强大,使用也很简单的,非常值得推荐。

控件的相关地址:

控件下载主页:http://mt.runon.cn/index.html

控件博客介绍:http://blog.sina.com.cn/s/articlelist_1340389911_0_1.html

应用这个控件,普通报表的打印效果如下所示:

上面两个报表的打印其实都差不多,都是打印部分的HTML内容,不过后者看起来要好一点,而且提供很完善的报表功能设置。

代码大致如下所示。

代码

<script language=”javascript”>
function Print(preview) {
var text = document.getElementById(content).innerHTML;
printConten(preview, text);
}
</script>

<script language=”javascript” src=”http://www.cnblogs.com/Scripts/CheckActivX.js”></script>
<object id=”LODOP” classid=”clsid:2105C259-1E0C-4534-8141-A753534CB4CA” width=0 height=0> </object>
<script language=”javascript”>
var LODOP = document.getElementById(LODOP); //这行 语句是为了符合DTD规范
CheckLodop();
</script>
<script language=”javascript” type=”text/javascript”>

function Preview() {//打印 预览
CreateLicenseData();
LODOP.SET_SHOW_MODE(
PREVIEW_IN_BROWSE, 1);
LODOP.PREVIEW();
};
function Setup() {//打印 维护 给用户调整位置
CreateLicenseData();
LODOP.PRINT_SETUP();
};
function Design() {//打印 设计 开发人员设置内容和位置
CreateLicenseData();
LODOP.PRINT_DESIGN();
};

function CreateLicenseData() {
LODOP.PRINT_INIT(
查询报表);
LODOP.ADD_PRINT_HTM(
20, 40, 610, 900, document.all(content).innerHTML);
LODOP.PREVIEW();
}
</script>

很多时候,我们也没的内容,都是通过CSS来控制美观的,所以有时候,我们打印部分HTML,没有这些样式的话,那么出来的Table格式和字体, 可能都会发生变化,不太好看。那么就需要进行HTML的样式设置。

如果给打印内容设置了样式,那么出来的界面效果就好很多了。

设置样式的代码如下所示。

代码

<script language=javascript type=text/javascript>

function Preview() {//打印预览
CreateLicenseData();
LODOP.SET_SHOW_MODE(
PREVIEW_IN_BROWSE, 1);
LODOP.PREVIEW();
};

function CreateLicenseData() {
LODOP.PRINT_INIT(申请处理单);
var strBodyStyle
= <link type=’text/css’ rel=’stylesheet’ href=’http://www.cnblogs.com/Themes/Default/style.css’ /><style><!–table { border:1;background-color: #CBCBCC } td {background-color:#FFFFFE;border: 1; } th { background-color:#F1F1F3;padding-left:5px;border:1}–></style>;
var strFormHtml
= strBodyStyle + <body> + document.getElementById(content).innerHTML + </body>;
LODOP.ADD_PRINT_HTM(
20, 40, 610, 900, strFormHtml);
LODOP.PREVIEW();
}
</script>

下一篇继续介绍下证件套打的打印功能。

主要研究技术:代码生成工具、Visio二次开发

转载请注明出处:
撰写人:伍华聪  http:
//www.iqidi.com

[转载]Web打印的解决方案之证件套打

mikel阅读(1037)

[转载]Web打印的解决方案之证件套打 – wuhuacong(伍华聪)的专栏 – 博客园.

由于以前未接触过套打,一直觉得套打是一个比较神秘和麻烦的事情,因为打印机的位置总是需要调整的,你总不能硬编码吧?但是如果位置可调,有需要直 观一些来处理,那就比较麻烦了。

在前面介绍过《Web打印的解决方案之普通报表打印》的一片文章中提到过那个打印控件Lodop,做起套打来感 觉还是挺方便的,至少位置调整界面不需要自己弄,位置嘛,也提供了自动保存的功能,不需要理会。

一般的套打,包含了几部分操作:打印预览、打印维护、打印设计。

打印预览和打印维护是面向终端用户的,打印维护是指内容不能修改删除、但位置可以调整,给不同的打印机不同的尺寸打印提供调整位置的可能性。

打印设计是面向开发人员的,开始需要通过这个功能来设计好套打的界面,就是根据套打证件的背景图片,大致摆放好各个内容的位置。

大致的实现代码如下所示:

<script language=”JavaScript>
var LODOP=document.getElementById(LODOP);//这行 语句是为了符合DTD规范
CheckLodop();
</script>
<script language=”JavaScript type=”text/javascript”>

function Preview2() {
CreateDataBill();
LODOP.PREVIEW();
};
function Setup2() {
CreateDataBill();
LODOP.PRINT_SETUP();
};
function Design2() {
CreateDataBill();
LODOP.PRINT_DESIGN();

};
function RealPrint() {
CreateDataBill();
if (LODOP.PRINTA())
alert(
已发出实 际打印命令!);
else
alert(
放弃打 印!);
};

function CreateDataBill() {
LODOP.SET_PRINT_PAPER(
10,10,762,533,打印控件 功能演示_Lodop功能_移动公司发票套打);
LODOP.ADD_PRINT_TEXT(
126,150,100,20,郭德刚);
LODOP.SET_PRINT_STYLEA(
1,FontColor,16711680);
LODOP.ADD_PRINT_TEXT(
151,150,100,20,13954885177);
LODOP.SET_PRINT_STYLEA(
2,FontColor,16711680);
LODOP.ADD_PRINT_TEXT(
125,584,99,20,发票打印 (第1次));
LODOP.SET_PRINT_STYLEA(
3,FontColor,16711680);
LODOP.ADD_PRINT_TEXT(
465,140,198,20,陆百柒拾 捌元叁角零分);
LODOP.SET_PRINT_STYLEA(
4,FontColor,16711680);
LODOP.ADD_PRINT_TEXT(
465,599,70,20,678.30);
LODOP.SET_PRINT_STYLEA(
5,FontColor,16711680);
LODOP.ADD_PRINT_TEXT(
496,408,59,20,H112063);
LODOP.SET_PRINT_STYLEA(
6,FontColor,16711680);
LODOP.ADD_PRINT_TEXT(
191,58,100,20,国内漫游 通话);
LODOP.SET_PRINT_STYLEA(
7,FontColor,16711680);
LODOP.ADD_PRINT_TEXT(
191,217,100,20,584.00);
LODOP.SET_PRINT_STYLEA(
8,FontColor,16711680);
LODOP.ADD_PRINT_TEXT(
222,58,100,20,增值业务 费);
LODOP.SET_PRINT_STYLEA(
9,FontColor,16711680);
LODOP.ADD_PRINT_TEXT(
222,217,100,20,48.30);
LODOP.SET_PRINT_STYLEA(
10,FontColor,16711680);
LODOP.ADD_PRINT_TEXT(
251,58,100,20,代收费);
LODOP.SET_PRINT_STYLEA(
11,FontColor,16711680);
LODOP.ADD_PRINT_TEXT(
251,217,100,20,50.00);
LODOP.SET_PRINT_STYLEA(
12,FontColor,16711680);
LODOP.ADD_PRINT_TEXT(
280,58,100,20,优惠费);
LODOP.SET_PRINT_STYLEA(
13,FontColor,16711680);
LODOP.ADD_PRINT_TEXT(
280,217,100,20,4.00);
LODOP.SET_PRINT_STYLEA(
14,FontColor,16711680);
LODOP.ADD_PRINT_TEXT(
98,101,150,20,101081005747319387);
LODOP.SET_PRINT_STYLEA(
15,FontColor,16711680);
LODOP.ADD_PRINT_TEXT(
97,307,150,20,2008 年10月19日 10:28:38);
LODOP.SET_PRINT_STYLEA(
16,FontColor,16711680);
LODOP.ADD_PRINT_TEXT(
152,584,103,20,138860016786);
LODOP.SET_PRINT_STYLEA(
17,FontColor,16711680);
LODOP.ADD_PRINT_TEXT(
95,571,112,20,06775516);
LODOP.SET_PRINT_STYLEA(
18,FontName,System);
LODOP.SET_PRINT_STYLEA(
18,FontColor,16711680);
LODOP.ADD_PRINT_TEXT(
496,135,183,20,2008 年09月(20080901-20080930));
LODOP.SET_PRINT_STYLEA(
19,FontColor,16711680);
LODOP.ADD_PRINT_TEXT(
496,572,112,20,-王府井 中心店营);
LODOP.SET_PRINT_STYLEA(
20,FontColor,16711680);
LODOP.ADD_PRINT_TEXT(
311,217,100,20,678.30);
LODOP.SET_PRINT_STYLEA(
21,FontColor,16711680);
LODOP.ADD_PRINT_TEXT(
311,58,100,20,费用合计);
LODOP.SET_PRINT_STYLEA(
22,FontColor,16711680);

LODOP.ADD_PRINT_SETUP_BKIMG(<img src=Report/ 证件背景.jpg’ />);
LODOP.SET_SHOW_MODE (
BKIMG_IN_PREVIEW,1);
}
</script>

其中大部分内容还是比较好理解的,不同的功能调用不同的函数Preview为预览、Setup为维护、Design为设计。

在套打的时候,注意需要通过下面代码来设置显示背景图片(打印的时候,是不打印背景的)。

LODOP.ADD_PRINT_SETUP_BKIMG(“<img src=Report/证件背景.jpg’ />“);
LODOP.SET_SHOW_MODE (“BKIMG_IN_PREVIEW”,1); //打印预览时是否包含背景图

另外,由于报表的内容都是写在HTML页面中的,因此在动态设置内容的时候,一可以用脚本来读取界面元素作为数据源,二可以通过后台代码自动生成 脚本代码,输出到前台页面中,看具体的需要了。

套打的预览界面大致如下图所示,其中蓝色部分是需要打印的内容,背景图片是一个发票的样板。

下面代码是通过脚本获取界面元素来取得相应的内容的,这种情况适合于界面上可能会修改一些打印的内容的情景。

LODOP.ADD_PRINT_TEXT(95, 695, 250, 52, document.getElementById(“txtCompanyName”).innerText); // 业户名称
LODOP.SET_PRINT_STYLEA(1, “FontSize”, 14);
LODOP.SET_PRINT_STYLEA(1, “Bold”, 1);

var licenseDate = document.getElementById(“txtLicenseDate”).value; //证件有效期
var licenseYear = “”;
var licenseMonth = “”;
var licenseDay = “”;
if (licenseDate != null && licenseDate != “”) {
licenseYear = licenseDate.split(“-“)[0];
licenseMonth = licenseDate.split(“-“)[1];
licenseDay = (licenseDate.split(“-“)[2]).substr(0, 2);
}

LODOP.ADD_PRINT_TEXT(396, 190, 46, 22, validateYear); // 有效期 结束 年
LODOP.SET_PRINT_STYLEA(6, “FontSize”, 11);
LODOP.SET_PRINT_STYLEA(6, “Bold”, 1);
LODOP.ADD_PRINT_TEXT(396, 253, 30, 22, validateMonth); // 有效期 结束 月
LODOP.SET_PRINT_STYLEA(7, “FontSize”, 11);
LODOP.SET_PRINT_STYLEA(7, “Bold”, 1);
LODOP.ADD_PRINT_TEXT(396, 304, 32, 22, validateDay); // 有效期 结束 日
LODOP.SET_PRINT_STYLEA(8, “FontSize”, 11);
LODOP.SET_PRINT_STYLEA(8, “Bold”, 1);

最后附上它的设计界面,其中生成代码功能可以生成用于静态HTML中的内容布局显示,做一定的修改调整就可以用在动态页面中了。非常有用的一个功 能。

主要研究技术:代码生成工具、Visio二次开发

转载请注明出处:
撰写人:伍华聪  http:
//www.iqidi.com