3

I am creating a WCF Rest Service to Upload Images from Mobile application. but i am getting The remote server returned an error: (400) Bad Request. can any one point me what i have done wrong. Following are my Definitions :

    [OperationContract]
    [WebInvoke(BodyStyle = WebMessageBodyStyle.Bare, UriTemplate = "/PostImage",Method ="POST")]

 PublicMessage PostImage(Upload obj);

[DataContract]
    public class Upload
    {
        [DataMember]
        public Stream File { get; set; }
    }

Service Definition :

public PublicMessage PostImage(Upload obj)
    {
        byte[] buffer = StreamToByte(obj.File);   //Function to convert the stream to byte array
     FileStream fs = new FileStream(@"D:\ShopMonkeyApp\Desert.jpg", FileMode.Create, FileAccess.ReadWrite);
        BinaryWriter bw = new BinaryWriter(fs);

        bw.Write(buffer);

        bw.Close();

        return new PublicMessage { Message = "Recieved the image on server" };
    }

Client Application :

string filePath = @"D:\ShopMonkeyApp\Desert.jpg";

        string url = "http://localhost:50268/shopmonkey.svc/PostImage/"; // Service Hosted in IIS

        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);

        request.Accept = "text/xml";

        request.Method = "POST";

        request.ContentType = "image/jpeg";

        using (Stream fileStream = File.OpenRead(filePath))

        using (Stream requestStream = request.GetRequestStream())
        {

            int bufferSize = 1024;

            byte[] buffer = new byte[bufferSize];

            int byteCount = 0;

            while ((byteCount = fileStream.Read(buffer, 0, bufferSize)) > 0)
            {

                requestStream.Write(buffer, 0, byteCount);

            }

        }

        string result;

        using (WebResponse response = request.GetResponse())

        using (StreamReader reader = new StreamReader(response.GetResponseStream()))
        {

            result = reader.ReadToEnd();

        }

        Console.WriteLine(result);

Web Config :

 <system.serviceModel>
        <services>
      <service name="ShopMonkey.ShopMonkey" behaviorConfiguration="ServiceBehaviour">
        <!-- Service Endpoints -->
        <!-- Unless fully qualified, address is relative to base address supplied above -->
        <endpoint address ="" binding="webHttpBinding" contract="ShopMonkey.IShopMonkey" behaviorConfiguration="web">
          <!-- 
              Upon deployment, the following identity element should be removed or replaced to reflect the 
              identity under which the deployed service runs.  If removed, WCF will infer an appropriate identity 
              automatically.behaviorConfiguration="web"
          -->
        </endpoint>
      </service>
    </services>

    <behaviors>
      <serviceBehaviors>
        <behavior name="ServiceBehaviour">
          <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
          <serviceMetadata httpGetEnabled="true"/>
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>
      </serviceBehaviors>
      <endpointBehaviors>
        <behavior name="web">
          <webHttp/>
          <dataContractSerializer maxItemsInObjectGraph="10000000"/>
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>

Thanks

Vijay

VijayMathew
  • 55
  • 1
  • 10
  • Also please clean up your code samples - indentation is very bad and there are obvious c# errors in the client code which will prevent it compiling in current state. – tom redfern Jul 16 '12 at 16:15
  • Try removing the body Style and see if it works. Also please post on how your StreamToByte method looks like? – Rajesh Jul 16 '12 at 16:22
  • I have updated my answer with sample code. Sorry for the delay. – Rajesh Jul 31 '12 at 10:02
  • Try this: http://stackoverflow.com/questions/9451141/uploading-an-image-using-wcf-restful-service-full-working-example/34913111#34913111 – Muhammad Shahzad Jan 21 '16 at 00:14

2 Answers2

1

Increasing the message queue length in web.config solves my issue.

<webHttpBinding>
        <binding name="streamWebHttpbinding" transferMode="Streamed"  maxReceivedMessageSize="1000000000000" receiveTimeout="01:00:00" sendTimeout="01:00:00" />
      </webHttpBinding>

Thanks to all

VijayMathew
  • 55
  • 1
  • 10
0

If you dont have any other properties on the Upload class then change the WCF service method to have a Stream param rather than wrapping it in a class as below:

[OperationContract]
[WebInvoke(UriTemplate = "/PostImage",Method ="POST")]
PublicMessage PostImage(Stream obj);

Then you can use the WebClient class to upload a file directly as shown below:

var c = new System.Net.WebClient();
c.OpenWrite(string.Concat("http://localhost:50268/shopmonkey.svc", "/PostImage"), "POST");
c.Headers[HttpRequestHeader.ContentType] = "image/jpeg";            
return c.UploadFile(string.Concat(serviceBaseUrl, resourceUrl), filePath);

Also refer to this link.

UPDATE :

Please find the sample to get your code working below:

[OperationContract]
[WebInvoke(UriTemplate = "/PostImage",Method ="POST")]
PublicMessage PostImage(Upload obj);

[DataContract]
public class Upload
{
    [DataMember]
    public MemoryStream FileContent { get; set; }
}

Now your method that implements the PostImage looks as follows:

public PublicMessage PostImage(Upload obj)
{
        byte[] buffer = new byte[obj.FileContent.Length];
        using (FileStream ms = new FileStream(@"D:\ShopMonkeyApp\Temp\Desert.jpg", FileMode.OpenOrCreate))
        {
            obj.FileContent.Position = 0;
            int read = fileInfo.Content.Read(buffer, 0, buffer.Length);
            ms.Write(buffer, 0, read);
        }

    return new PublicMessage { Message = "Recieved the image on server" };
}

Now since our server side code is complete now moving to the client side part that uploads your file to the server as below:

    private string ClientSample()
    {
            var uploadObject = new Upload();
            Image image = Image.FromFile(@"D:\ShopMonkeyApp\Desert.jpg");
            MemoryStream ms = new MemoryStream();
            uploadObject.FileContent = new MemoryStream();
            image.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
            ms.WriteTo(uploadObject.FileContent);
            ms.Close();

        string responseMessage = null;            
        var request = WebRequest.Create(http://localhost:50268/shopmonkey.svc/PostImage) as HttpWebRequest;
        if (request != null)
        {
            request.ContentType = "application/xml";
            request.Method = method;
        }

        if(method == "POST" && requestBody != null)
        {
            byte[] requestBodyBytes;
            requestBodyBytes = ToByteArrayUsingDataContractSer<Upload>(requestBody);
            request.ContentLength = requestBodyBytes.Length;
            using (Stream postStream = request.GetRequestStream())
                postStream.Write(requestBodyBytes, 0, requestBodyBytes.Length);                    
        }

        if (request != null)
        {
            var response = request.GetResponse() as HttpWebResponse;
            if(response.StatusCode == HttpStatusCode.OK)
            {
                Stream responseStream = response.GetResponseStream();
                if (responseStream != null)
                {
                    var reader = new StreamReader(responseStream);

                    responseMessage = reader.ReadToEnd();                        
                }
            }
            else
            {   
                responseMessage = response.StatusDescription;
            }
        }
    }

    private static byte[] ToByteArrayUsingDataContractSer<T>(T requestBody)
    {
        byte[] bytes = null;
        var serializer1 = new DataContractSerializer(typeof(T));            
        var ms1 = new MemoryStream();            
        serializer1.WriteObject(ms1, requestBody);
        ms1.Position = 0;
        var reader = new StreamReader(ms1);
        bytes = ms1.ToArray();
        return bytes;            
    }

NOTE: Make sure that your Upload object both on the client and server have the same namespace and properties defined so that you avoid any deserialization issues.

Community
  • 1
  • 1
Rajesh
  • 7,766
  • 5
  • 22
  • 35
  • hi rajesh i have tried your code but still i am getting The remote server returned an error: (400) Bad Request. any other way to do this? – VijayMathew Jul 17 '12 at 07:45
  • What is the image size that you are trying to upload? – Rajesh Jul 17 '12 at 08:41
  • thanks for ur reply .image size is 826kb.any special setting to be done in web.config file ? please let me know.. – VijayMathew Jul 17 '12 at 09:47
  • Enable Tracing (http://msdn.microsoft.com/en-us/library/ms733025.aspx) on your service and check the log file to know the reason behind the 400 Bad Request. Mostly would be due to the size and hence increase your readerQuotas settings for webHttpBinding. – Rajesh Jul 17 '12 at 10:47
  • rajesh now it is working i have increased the message queue length in web.config.but uploaded image shows error when opening it can u point me any error in stream to picture conversion?.. – VijayMathew Jul 19 '12 at 13:58