开发者

RESTful WCF Service That Needs to Upload Images And Multiple Arguments

I am in the process of developing a WCF service that needs to take in an image and 2 parameters. One being an int type, the other a string array. So this would be easy enough if it were only 1 parameter to send up, along with the image:

[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "UploadImages/{imageID}")]
public void UploadImages(int imageID, Stream image)
{                       
}

Now, in this scenario the image is in the body of the post. What if the consumer of the service needs to pass up a开发者_Python百科 third piece of data, how does that look and work in WCF?

  <system.serviceModel>
    <client>
    </client>
    <bindings>
      <webHttpBinding>
        <binding name="webHttpBindingStreamed" transferMode="Streamed"></binding>
      </webHttpBinding>      
    </bindings>
    <services> 
      <service name="ImageService">
        <endpoint address="" binding="webHttpBinding" behaviorConfiguration="MyWebHttpBehavior"  name="ImageServiceWebBinding" contract=IImageService" />
      </service>
    </services>
    <behaviors>      
      <endpointBehaviors>          
        <behavior name="MyWebHttpBehavior">
          <customWebHttp />
        </behavior>
      </endpointBehaviors>
      <serviceBehaviors>
        <behavior name="">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <extensions>
      <behaviorExtensions>
        <add name="customWebHttp" type="CustomHttpBehaviorExtensionElement, ImageUploader" />
      </behaviorExtensions>
    </extensions>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  </system.serviceModel>


You can pass the additional parameters in the URI as well, like in the example below. Or you can pass them as HTTP headers and fetch them using the WebOperationContext.Current.IncomingRequest.Headers property.

[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "UploadImages/{fileName}?imageId={imageID}")]
public void UploadImages(int imageID, string fileName, Stream image)
{                       
}

Update

Even if the parameter type is an array, you can also pass it in the query string - but you'll need to provide a QueryStringConverter which can decode that type. The example below shows that.

public class StackOverflow_6905108
{
    [ServiceContract]
    public class Service
    {
        [OperationContract]
        [WebInvoke(Method = "POST", UriTemplate = "UploadImages/{fileName}?array={array}")]
        public void UploadImages(int[] array, string fileName, Stream image)
        {
            Console.WriteLine("Array:");
            foreach (var item in array) Console.Write("{0} ", item);
            Console.WriteLine();
        }
    }
    public static void SendPost(string uri, string contentType, string body)
    {
        HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(uri);
        req.Method = "POST";
        req.ContentType = contentType;
        Stream reqStream = req.GetRequestStream();
        byte[] reqBytes = Encoding.UTF8.GetBytes(body);
        reqStream.Write(reqBytes, 0, reqBytes.Length);
        reqStream.Close();

        HttpWebResponse resp;
        try
        {
            resp = (HttpWebResponse)req.GetResponse();
        }
        catch (WebException e)
        {
            resp = (HttpWebResponse)e.Response;
        }

        Console.WriteLine("HTTP/{0} {1} {2}", resp.ProtocolVersion, (int)resp.StatusCode, resp.StatusDescription);
        foreach (string headerName in resp.Headers.AllKeys)
        {
            Console.WriteLine("{0}: {1}", headerName, resp.Headers[headerName]);
        }
        Console.WriteLine();
        Stream respStream = resp.GetResponseStream();
        Console.WriteLine(new StreamReader(respStream).ReadToEnd());

        Console.WriteLine();
        Console.WriteLine(" *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* ");
        Console.WriteLine();
    }
    class MyQueryStringConverter : QueryStringConverter
    {
        QueryStringConverter originalConverter;
        public MyQueryStringConverter(QueryStringConverter originalConverter)
        {
            this.originalConverter = originalConverter;
        }
        public override bool CanConvert(Type type)
        {
            return type == typeof(int[]) || base.CanConvert(type);
        }
        public override object ConvertStringToValue(string parameter, Type parameterType)
        {
            if (parameterType == typeof(int[]))
            {
                return parameter.Split(',').Select(x => int.Parse(x)).ToArray();
            }
            else
            {
                return base.ConvertStringToValue(parameter, parameterType);
            }
        }
    }
    public class MyWebHttpBehavior : WebHttpBehavior
    {
        protected override QueryStringConverter GetQueryStringConverter(OperationDescription operationDescription)
        {
            return new MyQueryStringConverter(base.GetQueryStringConverter(operationDescription));
        }
    }
    public static void Test()
    {
        string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
        ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
        host.AddServiceEndpoint(typeof(Service), new WebHttpBinding(), "").Behaviors.Add(new MyWebHttpBehavior());
        host.Open();
        Console.WriteLine("Host opened");

        SendPost(baseAddress + "/UploadImages/a.txt?array=1,2,3,4", "application/octet-stream", "The file contents");

        Console.Write("Press ENTER to close the host");
        Console.ReadLine();
        host.Close();
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜