参考他人实现文件传输

【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 }

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 }

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 }

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>

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

第七步出问题了:

直接复制App.config的内容,并点击运行,会以下出错(哈哈,肯定的呀)

右键App.config,选择“编辑WCF配置”,

修改第一个终结点的Contract

没有重复以上步骤,没有修改第二个终结点。

至此,App.config文件变成了:

 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="FileService.FileService">
24 <endpoint address="" binding="netTcpBinding" bindingConfiguration="MyTcpBinding"
25 contract="FileService.IFileService">
26 <identity>
27 <dns value="localhost" />
28 </identity>
29 </endpoint>
30 <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
31 <host>
32 <baseAddresses>
33 <add baseAddress="http://localhost:8733/Design_Time_Addresses/WcfTest/Service1/" />
34 <add baseAddress="net.tcp://localhost:8734/Design_Time_Addresses/WcfTest/Service1/" />
35 </baseAddresses>
36 </host>
37 </service>
38 </services>
39 <behaviors>
40 <serviceBehaviors>
41 <behavior>
42 <!-- 为避免泄漏元数据信息,
43 请在部署前将以下值设置为 false -->
44 <serviceMetadata httpGetEnabled="True" httpsGetEnabled="True"/>
45 <!-- 要接收故障异常详细信息以进行调试,
46 请将以下值设置为 true。在部署前设置为 false
47 以避免泄漏异常信息-->
48 <serviceDebug includeExceptionDetailInFaults="False" />
49 </behavior>
50 </serviceBehaviors>
51 </behaviors>
52 </system.serviceModel>
53
54 </configuration>

点击三角运行:

客户端:

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

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

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

 1 using System;
2 using System.Collections.Generic;
3 using System.ComponentModel;
4 using System.Data;
5 using System.Drawing;
6 using System.IO;
7 using System.Linq;
8 using System.Text;
9 using System.Windows.Forms;
10 using 客户端.FileService;
11
12 namespace 客户端
13 {
14 public partial class Form1 : Form
15 {
16 FileServiceClient client;
17 public Form1()
18 {
19 InitializeComponent();
20 client = new FileServiceClient();
21 }
22
23 private void button1_Click(object sender, EventArgs e)
24 {
25 OpenFileDialog Fdialog = new OpenFileDialog();
26
27 if (Fdialog.ShowDialog() == DialogResult.OK)
28 {
29
30 using (Stream fs = new FileStream(Fdialog.FileName, FileMode.Open, FileAccess.Read))
31 {
32 string message;
33 this.textBox1.Text = Fdialog.SafeFileName;
34 bool result = client.UpLoadFile(Fdialog.SafeFileName, fs.Length, fs, out message);
35
36 if (result == true)
37 {
38 MessageBox.Show("上传成功!");
39 }
40 else
41 {
42 MessageBox.Show(message);
43 }
44 }
45
46 }
47 }
48
49 private void button2_Click(object sender, EventArgs e)
50 {
51 string filename = this.textBox2.Text;
52 string path = System.AppDomain.CurrentDomain.BaseDirectory + @"\client\";
53 bool issuccess = false;
54 string message = "";
55 Stream filestream = new MemoryStream();
56 long filesize = client.DownLoadFile(filename, out issuccess, out message, out filestream);
57
58 if (issuccess)
59 {
60 if (!Directory.Exists(path))
61 {
62 Directory.CreateDirectory(path);
63 }
64
65 byte[] buffer = new byte[filesize];
66 FileStream fs = new FileStream(path + filename, FileMode.Create, FileAccess.Write);
67 int count = 0;
68 while ((count = filestream.Read(buffer, 0, buffer.Length)) > 0)
69 {
70 fs.Write(buffer, 0, count);
71 }
72
73 //清空缓冲区
74 fs.Flush();
75 //关闭流
76 fs.Close();
77 MessageBox.Show("下载成功!");
78
79 }
80 else
81 {
82 MessageBox.Show(message);
83 }
84 }
85 }
86 }

在保证“WCF测试客户端”开启的情况下,即可实现上传下载文件。

上传保存路径:service文件夹下(wcf服务的debug目录下service文件目录)

若使用console启动wcf,则在console的debug目录下的service文件夹目录;

下载路径:“客户端”的debug目录下的client文件夹下。

附console启动wcf代码(添加App.config文件)

 1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.ServiceModel;
5 using System.Text;
6
7 namespace ConsoleApp1
8 {
9 class Program
10 {
11 static void Main(string[] args)
12 {
13 using (ServiceHost host = new ServiceHost(typeof(FileService.FileService )))
14 {
15 host.Opened += delegate
16 {
17 Console.WriteLine("FileService.FileService已启动,按任意键停止服务");
18 };
19 host.Open();
20 Console.Read();
21 }
22 }
23 }
24 }

参考:

感谢!

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

https://www.cnblogs.com/caizl/p/4326016.html

https://www.cnblogs.com/wolf-sun/p/3277599.html

WCF的实现(方式二)的更多相关文章

  1. WCF技术剖析之二十九:换种不同的方式调用WCF服务[提供源代码下载]

    原文:WCF技术剖析之二十九:换种不同的方式调用WCF服务[提供源代码下载] 我们有两种典型的WCF调用方式:通过SvcUtil.exe(或者添加Web引用)导入发布的服务元数据生成服务代理相关的代码 ...

  2. WCF技术剖析之二十七: 如何将一个服务发布成WSDL[基于HTTP-GET的实现](提供模拟程序)

    原文:WCF技术剖析之二十七: 如何将一个服务发布成WSDL[基于HTTP-GET的实现](提供模拟程序) 基于HTTP-GET的元数据发布方式与基于WS-MEX原理类似,但是ServiceMetad ...

  3. WCF技术剖析之二十八:自己动手获取元数据[附源代码下载]

    原文:WCF技术剖析之二十八:自己动手获取元数据[附源代码下载] 元数据的发布方式决定了元数据的获取行为,WCF服务元数据架构体系通过ServiceMetadataBehavior实现了基于WS-ME ...

  4. WCF技术剖析之二十七: 如何将一个服务发布成WSDL[基于WS-MEX的实现](提供模拟程序)

    原文:WCF技术剖析之二十七: 如何将一个服务发布成WSDL[基于WS-MEX的实现](提供模拟程序) 通过<如何将一个服务发布成WSDL[编程篇]>的介绍我们知道了如何可以通过编程或者配 ...

  5. WCF技术剖析之二十七: 如何将一个服务发布成WSDL[编程篇]

    原文:WCF技术剖析之二十七: 如何将一个服务发布成WSDL[编程篇] 对于WCF服务端元数据架构体系来说,通过MetadataExporter将服务的终结点导出成MetadataSet(参考< ...

  6. WCF技术剖析之二十五: 元数据(Metadata)架构体系全景展现[元数据描述篇]

    原文:WCF技术剖析之二十五: 元数据(Metadata)架构体系全景展现[元数据描述篇] 在[WS标准篇]中我花了很大的篇幅介绍了WS-MEX以及与它相关的WS规范:WS-Policy.WS-Tra ...

  7. WCF技术剖析之二十三:服务实例(Service Instance)生命周期如何控制[下篇]

    原文:WCF技术剖析之二十三:服务实例(Service Instance)生命周期如何控制[下篇] 在[第2篇]中,我们深入剖析了单调(PerCall)模式下WCF对服务实例生命周期的控制,现在我们来 ...

  8. WCF技术剖析之二十二: 深入剖析WCF底层异常处理框架实现原理[中篇]

    原文:WCF技术剖析之二十二: 深入剖析WCF底层异常处理框架实现原理[中篇] 在[上篇]中,我们分别站在消息交换和编程的角度介绍了SOAP Fault和FaultException异常.在服务执行过 ...

  9. WCF技术剖析之二十一:WCF基本异常处理模式[下篇]

    原文:WCF技术剖析之二十一:WCF基本异常处理模式[下篇] 从FaultContractAttribute的定义我们可以看出,该特性可以在同一个目标对象上面多次应用(AllowMultiple = ...

  10. WCF技术剖析之二十一:WCF基本异常处理模式[中篇]

    原文:WCF技术剖析之二十一:WCF基本异常处理模式[中篇] 通过WCF基本的异常处理模式[上篇], 我们知道了:在默认的情况下,服务端在执行某个服务操作时抛出的异常(在这里指非FaultExcept ...

随机推荐

  1. .net 下SSE使用demo

    所谓SSE,就是浏览器向服务器发送一个HTTP请求,然后服务器不断单向地向浏览器推送"信息"(message).这种信息在格式上很简单,就是"信息"加上前缀&q ...

  2. LeetCode算法训练-回溯 491.递增子序列 46.全排列 47.全排列 II

    欢迎关注个人公众号:爱喝可可牛奶 LeetCode算法训练-回溯 491.递增子序列 46.全排列 47.全排列 II LeetCode 491. 递增子序列 分析 找出并返回所有数组中不同的递增子序 ...

  3. 爆肝200+小时,总结出的 Creator 3.x 入门修炼指南!全免费

    大家好,我是晓衡! 为了写这篇文章,给支持公众号的读者们一个交代,我准备了200+小时,公众号断更11天.我决定,不再选择逃避,不想再欺骗自己了. 2023新年开工,不到十天时间,接二连三有小伙伴找到 ...

  4. chai 3D 之网格对象

    推荐:将 NSDT场景编辑器 加入你的3D开发工具链 介绍 网格对象是由三角形和顶点组成的形状   在 CHAI3D 中,多边形网格是定义多面体对象形状的顶点和三角形的集合.   顶点是一个位置以及其 ...

  5. VM中centos7创建后无法上网问题

    在VMware 12 Pro上安装完CentOS7发现使用ping www.baidu.com无法ping通 使用以下命令: 1.cd /etc/sysconfig/network-scripts 然 ...

  6. CentOS 7.6 部署zabbix 6.0 支持Kubernetes

    # 基础信息 系统版本: CentOS Linux release 7.6.1810 (Core) 内核版本: 4.19.0-9.el7.ucloud.x86_64 # 听说最新版的zabbix6.0 ...

  7. Neo4j插件安装

    Neo4j插件安装 Author:wss Date:2022.6.9 Topic:Neo4j插件安装 一.前言 昨天再次安装Apoc插件,又去找之前看的教程,有些地方不够清晰要几个教程对比着看,想到可 ...

  8. CSS主要整理

    css主要整理 // 右侧悬浮导航 /* 侧栏开始 */ #home { position: relative } // 悬浮 #home .xf { width: 67.6923076923077p ...

  9. Java并发编程 —— synchronized关键字

    一.是什么?(作用) synchronized关键字解决了多个线程之间访问资源的同步性问题,保证了被其修饰的方法或是代码块在任意时刻只能有一个线程执行. 而在早期的Java版本中,synchroniz ...

  10. Newtonsoft.Json高级用法--转载至 焰尾迭 随笔

    本人只做搬运工,以这方便自己学习的态度!以下内容均为拷贝! 如有不适请联系本人! 本文原作者:焰尾迭 本文地址:http://www.cnblogs.com/yanweidie/p/4605212.h ...