引言

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

服务端

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

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

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

    [ServiceContract]
public interface IFileService
{ //上传文件
[OperationContract]
bool UpLoadFile(Stream filestream); //下载文件
[OperationContract]
Stream DownLoadFile(string downfile); }

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

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

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

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

    [ServiceContract]
public interface IFileService
{
//上传文件
[OperationContract]
UpFileResult UpLoadFile(UpFile filestream); //下载文件
[OperationContract]
DownFileResult DownLoadFile(DownFile downfile);
} [MessageContract]
public class DownFile
{
[MessageHeader]
public string FileName { get; set; }
} [MessageContract]
public class UpFileResult
{
[MessageHeader]
public bool IsSuccess { get; set; }
[MessageHeader]
public string Message { get; set; }
} [MessageContract]
public class UpFile
{
[MessageHeader]
public long FileSize { get; set; }
[MessageHeader]
public string FileName { get; set; }
[MessageBodyMember]
public Stream FileStream { get; set; }
} [MessageContract]
public class DownFileResult
{
[MessageHeader]
public long FileSize { get; set; }
[MessageHeader]
public bool IsSuccess { get; set; }
[MessageHeader]
public string Message { get; set; }
[MessageBodyMember]
public Stream FileStream { get; set; }
}

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

 public class FileService : IFileService
{
public UpFileResult UpLoadFile(UpFile filedata)
{ UpFileResult result = new UpFileResult(); string path = System.AppDomain.CurrentDomain.BaseDirectory +@"\service\"; if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
} byte[] buffer = new byte[filedata.FileSize]; FileStream fs = new FileStream(path + filedata.FileName, FileMode.Create, FileAccess.Write); int count = ;
while ((count = filedata.FileStream.Read(buffer, , buffer.Length)) > )
{
fs.Write(buffer, , count);
}
//清空缓冲区
fs.Flush();
//关闭流
fs.Close(); result.IsSuccess = true; return result; } //下载文件
public DownFileResult DownLoadFile(DownFile filedata)
{ DownFileResult result = new DownFileResult(); string path = System.AppDomain.CurrentDomain.BaseDirectory + @"\service\" + filedata.FileName; if (!File.Exists(path))
{
result.IsSuccess = false;
result.FileSize = ;
result.Message = "服务器不存在此文件";
result.FileStream = new MemoryStream();
return result;
}
Stream ms = new MemoryStream();
FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read);
fs.CopyTo(ms);
ms.Position = ; //重要,不为0的话,客户端读取有问题
result.IsSuccess = true;
result.FileSize = ms.Length;
result.FileStream = ms; fs.Flush();
fs.Close();
return result;
}
}

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

<?xml version="1.0" encoding="utf-8" ?>
<configuration> <appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" />
</system.web>
<!-- 部署服务库项目时,必须将配置文件的内容添加到
主机的 app.config 文件中。System.Configuration 不支持库的配置文件。-->
<system.serviceModel> <bindings>
<netTcpBinding>
<binding name="MyTcpBinding" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647" sendTimeout="00:30:00" transferMode="Streamed" >
<security mode="None"></security>
</binding>
</netTcpBinding>
</bindings> <services>
<service name="WcfTest.FileService">
<endpoint address="" binding="netTcpBinding" bindingConfiguration="MyTcpBinding" contract="WcfTest.IFileService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8733/Design_Time_Addresses/WcfTest/Service1/" />
<add baseAddress="net.tcp://localhost:8734/Design_Time_Addresses/WcfTest/Service1/" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- 为避免泄漏元数据信息,
请在部署前将以下值设置为 false -->
<serviceMetadata httpGetEnabled="True" httpsGetEnabled="True"/>
<!-- 要接收故障异常详细信息以进行调试,
请将以下值设置为 true。在部署前设置为 false
以避免泄漏异常信息-->
<serviceDebug includeExceptionDetailInFaults="False" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel> </configuration>

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

客户端

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

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

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

  public partial class MainWindow : Window
{ FileServiceClient client;
public MainWindow()
{
InitializeComponent();
client = new FileServiceClient();
} private void Button_Click_1(object sender, RoutedEventArgs e)
{
OpenFileDialog Fdialog = new OpenFileDialog(); if (Fdialog.ShowDialog().Value)
{ using (Stream fs = new FileStream(Fdialog.FileName, FileMode.Open, FileAccess.Read))
{
string message;
this.filepath.Text = Fdialog.SafeFileName;
bool result = client.UpLoadFile(Fdialog.SafeFileName, fs.Length,fs, out message); if (result == true)
{
MessageBox.Show("上传成功!");
}
else
{
MessageBox.Show(message);
}
} }
} private void Button_Click_2(object sender, RoutedEventArgs e)
{
string filename = this.filename.Text;
string path = System.AppDomain.CurrentDomain.BaseDirectory + @"\client\";
bool issuccess=false;
string message="";
Stream filestream=new MemoryStream();
long filesize = client.DownLoadFile(filename, out issuccess, out message, out filestream); if (issuccess)
{
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
} byte[] buffer = new byte[filesize];
FileStream fs = new FileStream(path + filename, FileMode.Create, FileAccess.Write);
int count = ;
while ((count = filestream.Read(buffer, , buffer.Length)) > )
{
fs.Write(buffer, , count);
} //清空缓冲区
fs.Flush();
//关闭流
fs.Close();
MessageBox.Show("下载成功!"); }
else
{ MessageBox.Show(message); } }
}

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

小结

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

【WCF】利用WCF实现上传下载文件服务的更多相关文章

  1. 【ARM-LInux开发】利用scp 远程上传下载文件/文件夹

    利用scp 远程上传下载文件/文件夹 scp [-1246BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file] [-l limit] [-o s ...

  2. 利用scp 远程上传下载文件/文件夹和ssh远程执行命令

    利用scp传输文件 1.从服务器下载文件scp username@servername:/path/filename /tmp/local_destination例如scp codinglog@192 ...

  3. linux利用scp远程上传下载文件/文件夹

    scp是secure copy的简写,用于在Linux下进行远程拷贝文件的命令,和它类似的命令有cp,不过cp只是在本机进行拷贝不能跨服务器,而且scp传输是加密的.可能会稍微影响一下速度. 当你服务 ...

  4. 利用scp 远程上传下载文件/文件夹

    scp [-1246BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file] [-l limit] [-o ssh_option] [-P port ...

  5. 利用 secureCRT 直接上传下载文件 (sz,rz)

    在window下向linux传送文件的方法. 首先在window中安装SecureCRT,然后在快速连接中建立一个到linux的连接,当然,你要先知道你的系统的ip,在终端中键入ifconfig可以查 ...

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

    使用WCF上传文件           在WCF没出现之前,我一直使用用WebService来上传文件,我不知道别人为什么要这么做,因为我们的文件服务器和网站后台和网站前台都不在同一个机器,操作人员觉 ...

  7. linux利用sh脚本上传下载文件到ftp服务器

    ####本地的/app/awsm/csv2 to ftp服务器上的/awsm/#### #!/bin/sh export today=`date +%Y-%m-%d` ftp -v -n 10.116 ...

  8. 如何利用京东云的对象存储(OSS)上传下载文件

    作者:刘冀 在公有云厂商里都有对象存储,京东云也不例外,而且也兼容S3的标准因此可以利用相关的工具去上传下载文件,本文主要记录一下利用CloudBerry Explorer for Amazon S3 ...

  9. rz和sz上传下载文件工具lrzsz

    ######################### rz和sz上传下载文件工具lrzsz ####################################################### ...

随机推荐

  1. Ubuntu系统vi编辑器上下左右键变ABCD的解决方法(转)

    首先卸载旧版本的vi编辑器: $sudo apt-get remove vim-common 然后安装新版vi即可: $sudo apt-get install vim Ubuntu自带有几种版本的v ...

  2. vim常规操作

    原文地址 三种模式 一般模式:可以进行复制.粘贴和删除等操作 编辑模式:按i或a进入编辑模式,按Esc回到一般模式 命令模式:按/或?或:进入命令模式,按Esc回到一般模式 移动操作 h j k l: ...

  3. "深入理解C语言" 指针

    本文对coolshell中的"深入理解C语言"这篇文章中提到的指针问题, 进行简要的分析. #include <stdio.h> int main(void){ ]; ...

  4. Linux Shell编程 awk命令

    概述 awk是一种编程语言,用于在linux/unix下对文本和数据进行处理.数据可以来自标准输入(stdin).一个或多个文件,或其它命令的输出.它支持用户自定义函数和动态正则表达式等先进功能,是l ...

  5. 树莓派连接DHT11温湿度传感器(python)

    介绍 DHT11作为一个廉价配件,同时包含了温度.湿度传感器,而且,编码使用也非常简单. 本文介绍如果在树莓派中使用 DHT11,代码是Python.如果有任何疑问,欢迎在下面留言. 接线 VCC接5 ...

  6. Raspberry Pi开发之旅-发送邮件记录时间及IP

    由于我使用树莓派的场景大多数是在没有显示器.只用terminal连接它的情况下,所以,它的IP地址有时会在重启之后变掉(DHCP的),导致我无法通过terminal连接上它.然后我又要很麻烦地登录路由 ...

  7. Ubuntu16.04下编译android6.0源码

    http://blog.csdn.net/cnliwy/article/details/52189349 作为一名合格的android开发人员,怎么能不会编译android源码呢!一定要来一次说编译就 ...

  8. ES6 随记(3.1)-- 字符串的拓展

    上一章请见: 1. ES6 随记(1)-- let 与 const 2. ES6 随记(2)-- 解构赋值 4. 拓展 a. 字符串的拓展 有些字符需要 4 个字节储存,比如 \uD83D\uDE80 ...

  9. Go 模板语法

    Sprig the useful template functions for Go templates (http://masterminds.github.io/sprig/) Github -  ...

  10. uiwebview 加载本地js、css、img,html从网站加载

    资源文件都是放在根目录下 1.index.html <html> <head> <title>My test Page</title> <link ...