您的位置:首页 > 其它

使用简单的wcf文件实现上传,下载文件到服务器

2014-02-10 16:27 1036 查看
wcf是微软开发出的用户数据通信的app接口,在.net framework3.0中与wpf,wf一同集成,是.net框架的一部分。

具体请参见点击打开链接

本文主要讲述了使用wcf服务契约来进行文件或者数据的服务器上传或者下载工作,使用的工具为vs2012(使用过程中发现了不少bug)。WCF是以契约来规定通信双方的沟通协议。双方必须定义相同的协议绑定才能实现沟通。本文使用基本的http支持,也就是basicHttpBinding。看具体步骤

1:搭建服务器,添加ServiceFile.svc文件



添加成功后,会在项目中增加一个该服务类对应的一个接口,IServiceFile,这个接口中定义的未实现方法就是将来要实现的服务代码,也是契约的定义声明,这里使用操作契约。

定义的接口代码:

// 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的接口名“IServiceFile”。
[ServiceContract]
public interface IServiceFile
{
/// <summary>
/// 上传操作
/// </summary>
/// <param name="fileInfo"></param>
/// <returns></returns>
[OperationContract]
CustomFileInfo UpLoadFileInfo(CustomFileInfo fileInfo);

/// <summary>
/// 获取文件操作
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
[OperationContract]
CustomFileInfo GetFileInfo(string fileName);
}

/// <summary>
/// 自定义文件属性类
/// </summary>
[DataContract]
public class CustomFileInfo
{
/// <summary>
/// 文件名称
/// </summary>
[DataMember]
public string Name { get; set; }

/// <summary>
/// 文件大小
/// </summary>
[DataMember]
public long Length { get; set; }

/// <summary>
/// 文件偏移量
/// </summary>
[DataMember]
public long OffSet { get; set; }

/// <summary>
/// 发送的字节
/// </summary>
[DataMember]
public byte[] SendByte { get; set; }
}


ServiceInfo.svc实现:

// 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码、svc 和配置文件中的类名“ServiceFile”。
// 注意: 为了启动 WCF 测试客户端以测试此服务,请在解决方案资源管理器中选择 ServiceFile.svc 或 ServiceFile.svc.cs,然后开始调试。
public class ServiceFile : IServiceFile
{
public CustomFileInfo UpLoadFileInfo(CustomFileInfo fileInfo)
{
// 获取服务器文件上传路径
string fileUpLoadPath = System.Web.Hosting.HostingEnvironment.MapPath("~/UpLoadFile/");
// 如需指定新的文件夹,需要进行创建操作。
Console.WriteLine("1");
// 创建FileStream对象
FileStream fs = new FileStream(fileUpLoadPath + fileInfo.Name, FileMode.OpenOrCreate);
Console.WriteLine("2");

long offSet = fileInfo.OffSet;
// 使用提供的流创建BinaryWriter对象
var binaryWriter = new BinaryWriter(fs, Encoding.UTF8);

binaryWriter.Seek((int)offSet, SeekOrigin.Begin);
binaryWriter.Write(fileInfo.SendByte);
fileInfo.OffSet = fs.Length;
fileInfo.SendByte = null;

binaryWriter.Close();
fs.Close();
Console.WriteLine("2");
return fileInfo;
}

public CustomFileInfo GetFileInfo(string fileName)
{
string filePath = System.Web.Hosting.HostingEnvironment.MapPath("~/UpLoadFile/") + fileName;
if (File.Exists(filePath))
{
var fs = new FileStream(filePath, FileMode.OpenOrCreate);
CustomFileInfo fileInfo = new CustomFileInfo
{
Name = fileName,
OffSet = fs.Length,
};
fs.Close();
return fileInfo;
}
return null;
}


服务端协议:

<span style="font-size:18px;"> <system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="FileTransferServicesBinding" maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" maxBufferPoolSize="2147483647"
transferMode="Streamed"  messageEncoding="Mtom"  sendTimeout="01:30:00">
<readerQuotas maxArrayLength="2147483647" maxStringContentLength="2147483647" maxBytesPerRead="2147483647"/>
</binding>
</basicHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="WebApplication1.ServiceFileBehavior"
name="WebApplication1.ServiceFile">
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="FileTransferServicesBinding" contract="WebApplication1.IServiceFile">
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="WebApplication1.ServiceFileBehavior">
<dataContractSerializer maxItemsInObjectGraph="2147483647"/>
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"></modules>
</system.webServer></span>


并成功部署到IIS(本文IIS版本为8.0),创建过程中创建存放上传文件的文件夹。

2:创建客户端项目看界面:



其实就三个操作,选择文件,上传文件,下载文件。

1:选择文件,最简单的弹出框选择文件,使用OpenFileDialog。

2:上传文件,使用的是独立线程。

定义客户端协议

客户端:
<?xml version="1.0"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IServiceFile" maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" maxBufferPoolSize="2147483647"
transferMode="Streamed" messageEncoding="Mtom">
<readerQuotas maxArrayLength="2147483647" maxStringContentLength="2147483647" maxBytesPerRead="2147483647"/>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://10.0.30.98:8001/ServiceFile.svc" binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_IServiceFile" contract="ULF.IServiceFile"
name="BasicHttpBinding_IServiceFile" />
</client>
</system.serviceModel>
</configuration>


上传代码:

 string filePath = this.txtFileName.Text;
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += worker_DoWork;
worker.WorkerReportsProgress = true;
worker.ProgressChanged += worker_ProgressChanged;
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
worker.RunWorkerAsync(filePath);
#region 独立线程
/// <summary>
/// 进度条更改
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (progressBar.InvokeRequired)
{
progressBar.Invoke((ThreadStart)delegate
{
progressBar.Value = e.ProgressPercentage;
});
}
else
{
progressBar.Value = e.ProgressPercentage;
progressBar.Update();
}
}
/// <summary>
/// 执行操作完成
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if ((bool)e.Result == false)
{

}
else
{
if (this.InvokeRequired)
{
this.Invoke((ThreadStart)delegate
{
MessageBox.Show("上传成功");
});
}
else
{
MessageBox.Show("上传成功");
}
}

if (progressBar.InvokeRequired)
{
progressBar.Invoke((ThreadStart)delegate
{
progressBar.Value = 0;
});
}
else
{
progressBar.Value = 0;
}

if (txtFileName.InvokeRequired)
{
txtFileName.Invoke((ThreadStart)delegate
{
this.txtFileName.Clear();
});
}
else
{
this.txtFileName.Clear();
}
if (this.btnUpload.InvokeRequired)
{
this.btnUpload.Invoke((ThreadStart)delegate
{
this.btnUpload.Enabled = true;
});
}
else
{
this.btnUpload.Enabled = true;
}

}

void worker_DoWork(object sender, DoWorkEventArgs e)
{
string path = e.Argument.ToString();
System.IO.FileInfo fileInfoIO = new System.IO.FileInfo(path);
// 要上传的文件地址
FileStream fs = File.OpenRead(fileInfoIO.FullName);
// 实例化服务客户的
ServiceFileClient client = new ServiceFileClient();
try
{
int maxSiz = 1024 * 100;
// 根据文件名获取服务器上的文件
CustomFileInfo file = client.GetFileInfo(fileInfoIO.Name);
if (file == null)
{
file = new CustomFileInfo();
file.OffSet = 0;
}
file.Name = fileInfoIO.Name;
file.Length = fs.Length;

if (file.Length == file.OffSet) //如果文件的长度等于文件的偏移量,说明文件已经上传完成
{
MessageBox.Show("该文件已存在");
e.Result = false;   // 设置异步操作结果为false
}
else
{
while (file.Length != file.OffSet)
{
file.SendByte = new byte[file.Length - file.OffSet <= maxSiz ? file.Length - file.OffSet : maxSiz]; //设置传递的数据的大小

fs.Position = file.OffSet; //设置本地文件数据的读取位置
fs.Read(file.SendByte, 0, file.SendByte.Length);//把数据写入到file.Data中
file = client.UpLoadFileInfo(file); //上传
//int percent = (int)((double)file.OffSet / (double)((long)file.Length)) * 100;
int percent = (int)(((double)file.OffSet / (double)((long)file.Length)) * 100);
(sender as BackgroundWorker).ReportProgress(percent);
}
// 移动文件到临时目录(此部分创建可以使用sqlserver数据库代替)
string address = string.Format(@"{0}\{1}", Helper.ServerFolderPath, file.Name);
fileInfoIO.CopyTo(address, true);
LoadUpLoadFile();  // 上传成功重新加载文件
e.Result = true;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
fs.Close();
fs.Dispose();
client.Close();
client.Abort();
}
}

/// <summary>
/// 选择文件对话框
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button2_Click(object sender, EventArgs e)
{
OpenFileDialog dialog = new OpenFileDialog();
dialog.InitialDirectory = "C:";
//dialog.Multiselect = true;
//dialog.Filter = "";
if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.Cancel)
{
return;
}
this.txtFileName.Text = dialog.FileName;
}
#endregion


3:下载文件 使用WebRequest,WebResponse对象获取Internet相应数据流大小,使用FileStream保存文件。下载使用了多线程。

下载代码:

Thread downLoadThread = new Thread(new ThreadStart(DownLoadFile));
downLoadThread.IsBackground = true;
downLoadThread.SetApartmentState(ApartmentState.STA);
downLoadThread.Name = "downLoadThreade";
downLoadThread.Start();
   #region 下载多线程
        private void DownLoadFile()
        {
            // 测试使用
            //string fileFullpath = "http://localhost:29700//UpLoadFile";
            string fileFullpath = Helper.ServerFilePath;
            // 获得DataGridView选中行
            DataGridViewRow selectedRow = this.dgvFiles.SelectedRows[0];
            string fileName = selectedRow.Cells[0].Value.ToString(); // 文件名称
            SaveFileDialog sfd = new SaveFileDialog();
            sfd.InitialDirectory = "C:";
            sfd.FileName = fileName;
            if (sfd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                fileFullpath += string.Format("//{0}", fileName);
                WebRequest request = WebRequest.Create(fileFullpath);
                WebResponse fs = null;
                try
                {
                    fs = request.GetResponse();
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
                long contentLength = fs.ContentLength;
                if (pbDownLoad.InvokeRequired)
                {
                    pbDownLoad.Invoke((ThreadStart)delegate
                    {
                        pbDownLoad.Maximum = (int)contentLength;
                    });
                }
                Stream st = fs.GetResponseStream();
                try
                {
                    byte[] byteLength = new byte[contentLength];
                    int allByte = (int)contentLength;
                    int startByte = 0;
                    while (contentLength > 0)
                    {
                        int downByte = st.Read(byteLength, startByte, allByte);
                        if (downByte == 0)
                        {
                            break;
                        }
                        startByte += downByte;
                        // 计算下载进度
                        //int percent = (int)(((double)startByte / ((long)(double)allByte)) * 100);
                        //(sender as BackgroundWorker).ReportProgress(percent);
                        if (pbDownLoad.InvokeRequired)
                        {
                            pbDownLoad.Invoke((ThreadStart)delegate
                            {
                                pbDownLoad.Value = startByte;
                            });
                        }
                        allByte -= downByte;
                    }
                    // 保存路径
                    string downLoadPath = sfd.FileName;
                    FileStream stream = new FileStream(downLoadPath, FileMode.OpenOrCreate, FileAccess.Write);
                    stream.Write(byteLength, 0, byteLength.Length);
                    stream.Close();
                    fs.Close();
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
                finally
                {
                    st.Close();
                    st.Dispose();
                    request.Abort();
                    Thread.Sleep(500);
                    MessageBox.Show("下载成功");
                    if (pbDownLoad.InvokeRequired)
                    {
                        pbDownLoad.Invoke((ThreadStart)delegate
                        {
                            pbDownLoad.Maximum = 0;
                        });
                    }
                }
            }
        #endregion


4:Helper类代码

public static class Helper
{
public static string ServerFilePath
{
get
{
// 获取客户端中定义的服务器地址
ClientSection clientSection = ConfigurationManager.GetSection("system.serviceModel/client") as ClientSection;
if (clientSection == null)
{
return "";
}
ChannelEndpointElementCollection collection = clientSection.Endpoints;
Uri uri = collection[0].Address;
return "http://" + uri.Authority + "//UpLoadFile";
}
}

/// <summary>
/// 服务器存放文件的文件夹地址
/// </summary>
public static string ServerFolderPath
{
//get { return @"E:\WCFCESHI1\UpLoadFile"; }
get { return @"C:\Test"; }
}
}
上传成功图:


经过测试,本地局域网可以上传<=2G的文件。应该可以满足需求。

下载成功图:



下载的时候对于选择文件名称有严格的要求,如果你的文件包含特殊字符或者其它wcf服务解析不了的字符,就会出现 404 not found 错误。

总结:继续努力工作,努力学习。

源码地址:WCF
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: