最近有个小项目,需求如下:
1:传真机把传真保存为.PDF文件放在某个特定的URI下文件夹中.
2:要监控这个文件夹下的文件变化,也就是有没有新的传真生成.(有新的传真会有新的.PDF文件生成).
3:监控到有新的传真,发邮件通知到相关的监控人员.
4:把新生成的文件上传到SFTP服务器上。
由于时间紧,且做得越简单越好.所以后来我决定做个Windows服务来完成这个小项目。
刚开始觉得这个项目应该很简单,不用花太多时间就可以完成的。但在做的过程中还是遇到不少小问题。
现在我把这个过程记下来,以便以后再用到(因为很少写这方面的程序,本人也是第一次写Windows服务程序)和希望能帮助有需要的朋友.
声明有很多内容也是参考网上的。
本人在VS2010下测试通过.
一:创建个解决方案,再创建window service项目,取项目名为ServiceTest
二:在新建好的项目中,找到Service1.cs,右击-->View Code(查看源代码)。在源代码中,OnStart方法是在服务启动时执行的,可以在这里编写服务要执行的业务逻辑代码;OnStop方法是在服务停止 时执行的,一般在这里编写终止服务线程或停止业务逻辑的代码等。
public partial class Service1 : ServiceBase
{
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
}
protected override void OnStop()
{
}
}
三:添加服务安装程序ProjectInstaller。
1)在Service1.cs的设计界面(可双击Service1.cs进入此界面),右击-->Add Installer(添加安装程序);
2)完成第一步,默认项目添加了ProjectInstaller.cs程序;
3)双击编辑文件ProjectInstaller.Designer.cs,更改下面代码:
a:在InitializeComponent方法中,添加代码
this.serviceProcessInstaller1.Account = System.ServiceProcess.ServiceAccount.LocalSystem;
ServiceAccount.LocalSystem可以选择不同的类型。
b:在InitializeComponent方法中,修改this.serviceInstaller1.ServiceName为服务类的名 称,默认为Service1,如果项目的服务类的名称更改了,注意一定要修改这个值,如:服务类的名称更为WinServiceTest后,对应修改代码 如下:
this.serviceInstaller1.ServiceName = "MyFirstService"; //服务类的名称
this.serviceInstaller1.DisplayName = "My First Service"; //安装后,在window服务管理里显示的名称
this.serviceInstaller1.Description = "For my first service testing"; //安装后,在window服务管理里显示的描述
this.serviceInstaller1.StartType = System.ServiceProcess.ServiceStartMode.Automatic;
ServiceStartMode.Automatic 可以选择不同的类型,有自动启动,手动和禁止三种方式。这里我选择自动启动,往往这类程序都需要自动启动.
四:添加window service安装的批处理命令
1)在项目添加一个文本文件,更名为install.bat,编辑文件的内容如下:
%SystemRoot%\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe .\WindowsServiceSolution.exe
Net Start MyFirstService
Pause
注意:这个Net Start MyFirstService 地方的MyFirstService就是上面这行代码里中设的名子this.serviceInstaller1.ServiceName = "MyFirstService";
2)在项目添加一个文本文件,更名为uninstall.bat,编辑文件的内容如下:
Net Stop MyFirstService
%SystemRoot%\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe /u WindowsServiceSolution.exe
Pause
补充说明:
- 另外,文件install.bat的属性里“Copy to Output Directory”默认为“Do not copy”,编译后,在debug的文件夹里找不到install.bat的,要更改为“Copy always”或者“Copy if newer”才能出现的。uninstall.bat也跟install.bat一样的。
- Net Stop MyFirstService和Net Stop MyFirstService分别是在卸载和安装时停止和启动服务。
- Pause是让.bat运行后暂停下可以看到服务的运行结果。
五、实际安装。
1)编译成功后,在debug文件夹中,双击install.bat完成安装;
2)安装成功后,在window的服务里,可看到此服务;
3)双击uninstall.bat可卸载此服务。
补充说明:也可以不用建install.bat文件,进行可以手动安装。
a) 运行cmd后进入到InstallUtil.exe路径下运行安装服务,如图。
再在光标处键入要安装的服务路径运行就行了。
这里我选的版本号为v4.0.30319,你可以选其它版本。
b)可以进入到C:\Windows\System32>下,用SC Create命令安装服务。如果不会SC命令的可以键入SC 回车,看下帮助.如下:
六: 监控.PDF文件,我们可以用FileSystemWatcher这个类来监控,直接上代码吧.
public void OnCreateFile()
{
FileSystemWatcher fileWatcher = new FileSystemWatcher();
fileWatcher.Path = WatcherDirectory;
fileWatcher.EnableRaisingEvents = true;
fileWatcher.Filter = “*.pdf”;
fileWatcher.Created += new FileSystemEventHandler(PDFFileWatcher_Created);
}
//注:这样就可以监控.pdf文件了,当有新的.pdf文件创建后就行调用FileWatcher_Created
void PDFFileWatcher_Created(object sender, FileSystemEventArgs e)
{
//log created file name and send mail.
string createdFileName= e.Name;
//这里就可以写发邮件的代码了.
}
七: 发邮件C#代码简单,还是上代码吧,如下:
MailMessage mailMessage = new MailMessage();
//mail infomation
mailMessage.Subject = "Test send mail ";
mailMessage.From = new MailAddress("发件人邮件地址", "发件人邮件地址");
mailMessage.Body = "testing";
mailMessage.BodyEncoding = Encoding.UTF8;
mailMessage.SubjectEncoding = Encoding.UTF8;
mailMessage.To.Add("收件人邮件地址");
mailMessage.IsBodyHtml = true;
mailMessage.Priority = MailPriority.High;
//smpt client message.
SmtpClient smtp = new SmtpClient();
smtp.Host = "smtp服务器地址";
smtp.Port = 端口号;
smtp.EnableSsl = false;
smtp.UseDefaultCredentials = false;
smtp.Credentials = new System.Net.NetworkCredential("发件人邮件地址","密码");
smtp.DeliveryMethod = SmtpDeliveryMethod.Network;
//send mail.
smtp.Send(mailMessage);
注:主要问题是在公司里测试时用公司里的SMTP服务器发送时,会遇到很多权限问题.
在这个小项目中害得我花了半天时间测试都没有成功发邮件,找了各种原因,后来问了NSS后才知道现在要申请开通权限(说明一下,以前不用开通的权限的,所以刚开始没有问他们). 所以如果在公司测试不能发邮件时,最好先问问NSS,看看有没有什么权限问题.不要轻易怀疑自己的代码。
八:上传文件到SFTP服务器上
在网上看了很多类似以下的c#代码,经测试没有成功。总是在GetRequestStream();
这个地方抛出异常:没有权限访问。
而我用WinSCP软件能够连接到SFTP服务上,且能上传,下载文件和一些其它操作. 可是用的是同样的登录名和密码,项目紧也没有多少时间去考虑这个问题了,不知道是不是因为c#的这个程序不支持SFTP.如有知道者请告之,感谢!
FileInfo fileInf =
new
FileInfo(filename);
string
uri = ftpURI + fileInf.Name;
FtpWebRequest reqFTP;
reqFTP = (FtpWebRequest)FtpWebRequest.Create(
new
Uri(uri));
reqFTP.Credentials =
new
NetworkCredential(ftpUserID, ftpPassword);
reqFTP.KeepAlive =
false
;
reqFTP.Method = WebRequestMethods.Ftp.UploadFile;
reqFTP.UseBinary =
true
;
reqFTP.ContentLength = fileInf.Length;
int
buffLength = 2048;
byte
[] buff =
new
byte
[buffLength];
int
contentLen;
FileStream fs = fileInf.OpenRead();
try
{
Stream strm = reqFTP.GetRequestStream();
contentLen = fs.Read(buff, 0, buffLength);
while
(contentLen != 0)
{
strm.Write(buff, 0, contentLen);
contentLen = fs.Read(buff, 0, buffLength);
}
strm.Close();
fs.Close();
}
catch
(Exception ex)
{
Insert_Standard_ErrorLog.Insert(
"FtpWeb"
,
"Upload Error --> "
+ ex.Message);
}
所以我后来我只能改用WinSCP来上传和下载。
步骤:进入运行 cmd命令
1)进入到c:\program files\WinSCP3>WinSCP.exe
2)再键入这些参数运行,就可以把文件上传到服务器了
注:对以上参数解析
/console /command 表示命令运行。
"option batch continue" 批处理一直进行,直到处理结束。
"option confirm off" 不弹出确认。
"open sftp://UserId:Password@SFTPIP:Port" 分别为用户名,密码,sftp ip和端口号。格式固定这样写的。
"option transfer binary" 以二进制方式传送。
"put d:\sourcefolder test" d:\sourcefolder要上传的文件路径;test为SFTP服务器上目标文件夹,如果test省略,刚在SFTP上生成与sourcefolder同名的文件夹. 如果d:\sourcefolder换成d:\sourcefolder\filename.*这样的格式,就会上传特定的文件到服务器的当出目录。
"close" 关闭连接。
"exit" 退出。
代码整合一下,就实现了文件的监控,发邮件,上传到SFTP服务器整功能了。
总节:虽然是小项目,但是要注意的地方也不少。特别是对像我这样初次做这类程序的人,做好了也不容易。
希望对和我有相同需求的朋友,有所帮助!