如何上传文件托管在IIS中的.NET 3.5 WCF服务?上传文件、IIS、NET、WCF

2023-09-07 03:59:12 作者:谁念西风独自凉

我一直在撕扯我的头发,有一段时间了。有人可以提供一个非常简单的如何将文件上传到服务器是在IIS中的WCF服务示例(或链接到一个工作示例)。

I've been ripping my hair out for a while now. Can someone provide a really simple example (or a link to a working example) of how to upload a file to a WCF service hosted in IIS.

我已经开始用简单的东西。我想通过POST调用的URL从客户端,传递文件的名称和文件发送为好。所以我增加了以下的合同:

I've started with something simple. I want to call a URL from a client via POST, pass the name of the file and send the file as well. So I added the following to the contract:

[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "/UploadFile?fileName={fileName}")]
void Upload(string fileName, Stream stream);

在.svc文件的实现了它:

The implemented it in the .svc file:

public void Upload(string fileName, Stream stream)
{
    Debug.WriteLine((fileName));
}

随即,我一旦运行该项目得到一个错误:

Immediately, I get an error upon running the project:

对于操作上传请求是一个流中的操作必须有一个参数,其类型为流。

不知道从哪里何去何从。希望能看到实际的工作示例。

Not sure where to go from here. Would love to see an actual working example.

P.S。我这样做是.NET 4 WCF 4,它似乎简单了很多,但我不得不降级。在.NET 3.5中,我失去了一些东西。

P.S. I did this in .NET 4 with WCF 4 and it seemed a lot simpler, but I've had to downgrade. In .NET 3.5, I am missing something.

推荐答案

为了为它工作,你需要定义一个具有约束力的兼容端点与的WebHttpBinding 并有 WebHttpBehavior 添加到它。该消息可能是一个红色的鲱鱼,这是它,如果你浏览到服务的基址旧的错误,如果你启用了元数据,它会显示出来。另一个问题是,如果你希望能够上传的任意的文件类型(包括JSON和XML),你需要定义一个WebContentTypeMapper告诉WCF不要试着去了解你的文件(详细信息在http://blogs.msdn.com/b/carlosfigueira/archive/2008/04/17/wcf-raw-programming-model-receiving-arbitrary-data.aspx).

In order for it to work you need to define an endpoint with a binding compatible with WebHttpBinding and which has the WebHttpBehavior added to it. The message may be a red herring, it's an old bug which if you browse to the service base address, and if you have metadata enabled, it will show up. Another issue is that if you want to be able to upload any file type (including JSON and XML), you'll need to define a WebContentTypeMapper to tell WCF not to try to understand your file (more info at http://blogs.msdn.com/b/carlosfigueira/archive/2008/04/17/wcf-raw-programming-model-receiving-arbitrary-data.aspx).

这是一个完整的例子做到这一点。 3.5最大的问题是,ContentTypeMapper属性不上的WebHttpBinding存在,所以你需要使用自定义进行装订。这code定义使用自定义的 ServiceHostFactory 端点,但它可以使用配置也被定义。

This is a complete example which does that. The biggest problem with 3.5 is that the ContentTypeMapper property doesn't exist on the WebHttpBinding, so you need to use a custom binding for that. This code defines the endpoint using a custom ServiceHostFactory, but it could be defined using config as well.

Service.svc

<%@ ServiceHost Language="C#" Debug="true" Service="MyNamespace.MyService" Factory="MyNamespace.MyFactory" %>

的Service.cs

using System;
using System.Diagnostics;
using System.IO;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Web;

public class MyNamespace
{
    [ServiceContract]
    public interface IUploader
    {
        [OperationContract]
        [WebInvoke(Method = "POST", UriTemplate = "/UploadFile?fileName={fileName}")]
        void Upload(string fileName, Stream stream);
    }

    public class Service : IUploader
    {
        public void Upload(string fileName, Stream stream)
        {
            Debug.WriteLine(fileName);
        }
    }

    public class MyFactory : ServiceHostFactory
    {
        protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
        {
            return new MyServiceHost(serviceType, baseAddresses);
        }

        class MyRawMapper : WebContentTypeMapper
        {
            public override WebContentFormat GetMessageFormatForContentType(string contentType)
            {
                return WebContentFormat.Raw;
            }
        }

        public class MyServiceHost : ServiceHost
        {
            public MyServiceHost(Type serviceType, Uri[] baseAddresses)
                : base(serviceType, baseAddresses) { }

            protected override void OnOpening()
            {
                base.OnOpening();

                CustomBinding binding = new CustomBinding(new WebHttpBinding());
                binding.Elements.Find<WebMessageEncodingBindingElement>().ContentTypeMapper = new MyRawMapper();
                ServiceEndpoint endpoint = this.AddServiceEndpoint(typeof(IUploader), binding, "");
                endpoint.Behaviors.Add(new WebHttpBehavior());
            }
        }
    }
}