利用WCF实现上传下载文件服务

引言

    前段时间,用WCF做了一个小项目,其中涉及到文件的上传下载。出于复习巩固的目的,今天简单梳理了一下,整理出来,下面展示如何一步步实现一个上传下载的WCF服务。

服务端

      1.首先新建一个名为FileService的WCF服务库项目,如下图:

       技术分享

      2.将Service,IService重命名为FileService,IFileService,如下图:

        技术分享

      3.打开IFileService.cs,定义两个方法,如下:

技术分享

 
  1. [ServiceContract]

  2. public interface IFileService

  3. {

  4.  
  5. //上传文件

  6. [OperationContract]

  7. bool UpLoadFile(Stream filestream);

  8.  
  9. //下载文件

  10. [OperationContract]

  11. Stream DownLoadFile(string downfile);

  12.  
  13. }

View Code

     4.上面方法定义了输入参数和返回参数,但是实际项目中往往是不够的,我们需要增加其他参数,如文件名,文件大小之类。然而WCF中有限定,如下:

  • 保留要进行流处理的数据的参数必须是方法中的唯一参数。 例如,如果要对输入消息进行流处理,则该操作必须正好具有一个输入参数。 同样,如果要对输出消息进行流处理,则该操作必须正好具有一个输出参数或一个返回值。

  • 参数和返回值的类型中至少有一个必须是 StreamMessage 或 IXmlSerializable

     所以我们需要用Message契约特性包装一下参数,修改代码如下:

技术分享

 
  1. [ServiceContract]

  2. public interface IFileService

  3. {

  4. //上传文件

  5. [OperationContract]

  6. UpFileResult UpLoadFile(UpFile filestream);

  7.  
  8. //下载文件

  9. [OperationContract]

  10. DownFileResult DownLoadFile(DownFile downfile);

  11. }

  12.  
  13. [MessageContract]

  14. public class DownFile

  15. {

  16. [MessageHeader]

  17. public string FileName { get; set; }

  18. }

  19.  
  20. [MessageContract]

  21. public class UpFileResult

  22. {

  23. [MessageHeader]

  24. public bool IsSuccess { get; set; }

  25. [MessageHeader]

  26. public string Message { get; set; }

  27. }

  28.  
  29. [MessageContract]

  30. public class UpFile

  31. {

  32. [MessageHeader]

  33. public long FileSize { get; set; }

  34. [MessageHeader]

  35. public string FileName { get; set; }

  36. [MessageBodyMember]

  37. public Stream FileStream { get; set; }

  38. }

  39.  
  40. [MessageContract]

  41. public class DownFileResult

  42. {

  43. [MessageHeader]

  44. public long FileSize { get; set; }

  45. [MessageHeader]

  46. public bool IsSuccess { get; set; }

  47. [MessageHeader]

  48. public string Message { get; set; }

  49. [MessageBodyMember]

  50. public Stream FileStream { get; set; }

  51. }

View Code

    5.现在服务契约定义好了,接下来实现契约的接口。打开FileService.cs文件,编写代码,实现服务端的上传下载文件服务,代码如下:

技术分享

 
  1. public class FileService : IFileService

  2. {

  3. public UpFileResult UpLoadFile(UpFile filedata)

  4. {

  5.  
  6. UpFileResult result = new UpFileResult();

  7.  
  8. string path = System.AppDomain.CurrentDomain.BaseDirectory +@"\service\";

  9.  
  10. if (!Directory.Exists(path))

  11. {

  12. Directory.CreateDirectory(path);

  13. }

  14.  
  15. byte[] buffer = new byte[filedata.FileSize];

  16.  
  17. FileStream fs = new FileStream(path + filedata.FileName, FileMode.Create, FileAccess.Write);

  18.  
  19. int count = 0;

  20. while ((count = filedata.FileStream.Read(buffer, 0, buffer.Length)) > 0)

  21. {

  22. fs.Write(buffer, 0, count);

  23. }

  24. //清空缓冲区

  25. fs.Flush();

  26. //关闭流

  27. fs.Close();

  28.  
  29. result.IsSuccess = true;

  30.  
  31. return result;

  32.  
  33. }

  34.  
  35. //下载文件

  36. public DownFileResult DownLoadFile(DownFile filedata)

  37. {

  38.  
  39. DownFileResult result = new DownFileResult();

  40.  
  41. string path = System.AppDomain.CurrentDomain.BaseDirectory + @"\service\" + filedata.FileName;

  42.  
  43. if (!File.Exists(path))

  44. {

  45. result.IsSuccess = false;

  46. result.FileSize = 0;

  47. result.Message = "服务器不存在此文件";

  48. result.FileStream = new MemoryStream();

  49. return result;

  50. }

  51. Stream ms = new MemoryStream();

  52. FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read);

  53. fs.CopyTo(ms);

  54. ms.Position = 0; //重要,不为0的话,客户端读取有问题

  55. result.IsSuccess = true;

  56. result.FileSize = ms.Length;

  57. result.FileStream = ms;

  58.  
  59. fs.Flush();

  60. fs.Close();

  61. return result;

  62. }

  63. }

View Code

    6.至此,具体实现代码完成,但是我们还需要配置一下App.config,设置地址,契约和绑定。这里绑定采用NetTcpBinding,我们还需要为NetTcpBinding具体配置,如maxReceivedMessageSize(配置最大接收文件大小),transferMode(传输模式,这里是Streamed)等。最终代码如下:

技术分享

 
  1. <?xml version="1.0" encoding="utf-8" ?>

  2. <configuration>

  3.  
  4. <appSettings>

  5. <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />

  6. </appSettings>

  7. <system.web>

  8. <compilation debug="true" />

  9. </system.web>

  10. <!-- 部署服务库项目时,必须将配置文件的内容添加到

  11. 主机的 app.config 文件中。System.Configuration 不支持库的配置文件。-->

  12. <system.serviceModel>

  13.  
  14. <bindings>

  15. <netTcpBinding>

  16. <binding name="MyTcpBinding" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647" sendTimeout="00:30:00" transferMode="Streamed" >

  17. <security mode="None"></security>

  18. </binding>

  19. </netTcpBinding>

  20. </bindings>

  21.  
  22. <services>

  23. <service name="WcfTest.FileService">

  24. <endpoint address="" binding="netTcpBinding" bindingConfiguration="MyTcpBinding" contract="WcfTest.IFileService">

  25. <identity>

  26. <dns value="localhost" />

  27. </identity>

  28. </endpoint>

  29. <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />

  30. <host>

  31. <baseAddresses>

  32. <add baseAddress="http://localhost:8733/Design_Time_Addresses/WcfTest/Service1/" />

  33. <add baseAddress="net.tcp://localhost:8734/Design_Time_Addresses/WcfTest/Service1/" />

  34. </baseAddresses>

  35. </host>

  36. </service>

  37. </services>

  38. <behaviors>

  39. <serviceBehaviors>

  40. <behavior>

  41. <!-- 为避免泄漏元数据信息,

  42. 请在部署前将以下值设置为 false -->

  43. <serviceMetadata httpGetEnabled="True" httpsGetEnabled="True"/>

  44. <!-- 要接收故障异常详细信息以进行调试,

  45. 请将以下值设置为 true。在部署前设置为 false

  46. 以避免泄漏异常信息-->

  47. <serviceDebug includeExceptionDetailInFaults="False" />

  48. </behavior>

  49. </serviceBehaviors>

  50. </behaviors>

  51. </system.serviceModel>

  52.  
  53. </configuration>

View Code

    7.这时可以运行服务,如果没有问题的话,会看到如下截图。

   技术分享

客户端

  1.首先新建一个WPF应用程序,在MainWindow.xaml添加控件,得到下图:

      技术分享

     2.在引用中右击,选择添加服务引用,出现对话框,我们需要填上刚才打开的服务的地址,然后按旁边的转到,会看到显示找到服务,接着更改命名空间为FileService,得到如下图。

     技术分享

    2.按确定之后,在资源管理器里的引用下面会多出一个FileService命名空间,里面包含我们的刚才写的FileServiceClient服务代理类 ,现在我们可以通过它调用服务了。编写代码如下:

技术分享

 
  1. public partial class MainWindow : Window

  2. {

  3.  
  4. FileServiceClient client;

  5. public MainWindow()

  6. {

  7. InitializeComponent();

  8. client = new FileServiceClient();

  9. }

  10.  
  11. private void Button_Click_1(object sender, RoutedEventArgs e)

  12. {

  13. OpenFileDialog Fdialog = new OpenFileDialog();

  14.  
  15. if (Fdialog.ShowDialog().Value)

  16. {

  17.  
  18. using (Stream fs = new FileStream(Fdialog.FileName, FileMode.Open, FileAccess.Read))

  19. {

  20. string message;

  21. this.filepath.Text = Fdialog.SafeFileName;

  22. bool result = client.UpLoadFile(Fdialog.SafeFileName, fs.Length,fs, out message);

  23.  
  24. if (result == true)

  25. {

  26. MessageBox.Show("上传成功!");

  27. }

  28. else

  29. {

  30. MessageBox.Show(message);

  31. }

  32. }

  33.  
  34. }

  35. }

  36.  
  37. private void Button_Click_2(object sender, RoutedEventArgs e)

  38. {

  39. string filename = this.filename.Text;

  40. string path = System.AppDomain.CurrentDomain.BaseDirectory + @"\client\";

  41. bool issuccess=false;

  42. string message="";

  43. Stream filestream=new MemoryStream();

  44. long filesize = client.DownLoadFile(filename, out issuccess, out message, out filestream);

  45.  
  46. if (issuccess)

  47. {

  48. if (!Directory.Exists(path))

  49. {

  50. Directory.CreateDirectory(path);

  51. }

  52.  
  53. byte[] buffer = new byte[filesize];

  54. FileStream fs = new FileStream(path + filename, FileMode.Create, FileAccess.Write);

  55. int count = 0;

  56. while ((count = filestream.Read(buffer, 0, buffer.Length)) > 0)

  57. {

  58. fs.Write(buffer, 0, count);

  59. }

  60.  
  61. //清空缓冲区

  62. fs.Flush();

  63. //关闭流

  64. fs.Close();

  65. MessageBox.Show("下载成功!");

  66.  
  67. }

  68. else

  69. {

  70.  
  71. MessageBox.Show(message);

  72.  
  73. }

  74.  
  75.  
  76. }

  77. }

View Code

 

   3.运行程序,上传下载文件,会在服务端和客服端运行目录下分别找到上传的文件和下载的文件,测试通过。界面如下:

   技术分享技术分享

小结

  本文通过图文一步步介绍了如何实现上传下载文件功能,其中涉及到WCF知识点其实是不少的,但是都是简单地带过。如果有不明白的地方,可以查阅Google,百度,也可以留言。如果您有更好的建议,请不吝指教,感激不尽!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值