WCF REST File Upload

2020-03-05 03:02发布

问题:

I am developing a WCF web service that needs to be able to upload files among other things.

Currently my method for adding a 'floorplan' item looks like:

[OperationContract]
[WebInvoke(Method = "GET",
    ResponseFormat = WebMessageFormat.Xml,
    BodyStyle = WebMessageBodyStyle.Wrapped,
    UriTemplate = "Floorplan?token={token}&floorplan={floorplan}")]
string XmlInputFloorplan(string token, string floorplan);

I need to alter it so that an image will be uploaded as a part of this call that can be used in a method like:

public static Guid AddFile(byte[] stream, string type);

In this case the byte[] is the content of the image. The resulting guid is then passed on to the data layer and the addition of the floorplan is finalized.

So I need to figure out two things:

1) How should I alter the XmlInputFloorplan interface method so that it also allows for an image as a parameter?
2) How do I consume the service after the alteration?

Thanks!

Here is how I solved it:

[OperationContract]
[WebInvoke(Method = "POST",
    ResponseFormat = WebMessageFormat.Xml,
    BodyStyle = WebMessageBodyStyle.Wrapped,
    UriTemplate = "Floorplan")]
XmlDocument XmlInputFloorplan(Stream content);

Expects an input XML like:

<?xml version="1.0" encoding="us-ascii" ?>
<CreateFloorplanRequest>
  <Token></Token>
  <Floorplan></Floorplan>
  <Image></Image>
</CreateFloorplanRequest>

And the Image contains a base 64 encoded string that represents the image file which I convert to byte[] via:

XmlDocument doc = new XmlDocument();
doc.Load(content);
content.Close();

XmlElement body = doc.DocumentElement;
byte[] imageBytes = Convert.FromBase64String(body.ChildNodes[2].InnerText);

In order to allow for this I had to configure the Web.config like so:

<service behaviorConfiguration="someBehavior" name="blah.blahblah">
    <endpoint 
        address="DataEntry" 
        behaviorConfiguration="web" 
        binding="webHttpBinding" 
        bindingConfiguration="basicBinding" 
        contract="blah.IDataEntry" />
</service>

<bindings>
  <webHttpBinding>
    <binding name="basicBinding" maxReceivedMessageSize ="50000000"
        maxBufferPoolSize="50000000" >
      <readerQuotas maxDepth="500000000"
        maxArrayLength="500000000" maxBytesPerRead="500000000"
        maxNameTableCharCount="500000000" maxStringContentLength="500000000"/>
      <security mode="None"/>
    </binding>
  </webHttpBinding>
</bindings>

回答1:

Your URI will look completely different - something like this (I'm having to make some guesses)

[OperationContract]
[WebInvoke(Method = "POST",
           ResponseFormat = WebMessageFormat.Xml,
           BodyStyle = WebMessageBodyStyle.Wrapped,
           UriTemplate = "Floorplan?type={type}&token={token}&floorplan={floorplan}")]
Guid XmlInputFloorplan(string type, string token, string floorplan, Stream image);

I've taken the liberty of changing the byte array to a Stream which gives you the option of streaming the image should it be large (but doesn' t require streaming)

To call this you can create a WebRequest with the correct Uri (including the type, token and floorplan) and perform a POST. Make the content type the right one for the format of the image (jpeg, png, etc) and get the request stream copying the image into it. Then call GetResponse on the WebRequest to make the HTTP request



回答2:

You wont be able to pass the byte array as a GET. Passing that much data in the request string wouldent work. You will need to do a http POST