0

I am trying to upload an image through wcf from angular frontend. It is working fine and I am receiving a success message too but the image saved is not opening in image viewer of any other image program.

the code to save the received file stream is copied from stackoverflow previous answer but that answer was very old.

 public string PostImage(Stream stream)
            {
                using (var f = new FileStream(@"C:\Temp\Sample.jpg", FileMode.OpenOrCreate))
            {
                stream.CopyTo(f);
            }
            stream.Close();
            return "Recieved the image on server";
            }
}

How can I save the file in correct format.

Angular files are

app.component.ts

import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';


@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  fileData: File = null;
constructor(private http: HttpClient) { }

fileProgress(fileInput: any) {
    this.fileData = fileInput.target.files[0] as File;
}

onSubmit() {
    console.log('Test');
    const formData = new FormData();
    formData.append('file', this.fileData);
    this.http.post('http://localhost:50604/Service1.svc/PostImage', formData, {responseType: 'text'})
      .subscribe(res => {
        console.log(res);
        alert('SUCCESS !!');
      });
}
}

It appears that this service is saving only 139kb file and stream is breaking. The webconfig binding settings are as follows

<webHttpBinding>
        <binding name="largeMessage" maxReceivedMessageSize="1000000000000" transferMode="Streamed" maxBufferPoolSize="2147483647" maxBufferSize="2147483647" closeTimeout="00:03:00" openTimeout="00:03:00" receiveTimeout="00:10:00" sendTimeout="00:03:00">
          <readerQuotas maxStringContentLength="2147483647" maxArrayLength="1000000000" maxBytesPerRead="2147483647" />
          <security mode="None"/>
        </binding>
      </webHttpBinding>
Hasan Zubairi
  • 1,037
  • 4
  • 23
  • 57

2 Answers2

0

The code is only copying the first 10,000 bytes of your input stream to C:\Temp\Sample.jpg. You might have more success with the following:

public string PostImage(Stream stream)
{
    using (var f = new FileStream(@"C:\Temp\Sample.jpg", FileMode.OpenOrCreate))
    {
        stream.CopyTo(f);
    }
    stream.Close();
    return "Recieved the image on server";
}
AlwaysLearning
  • 7,915
  • 5
  • 27
  • 35
  • Thanks for your answer .Image is saving but not in correct format. Giving same error as before unsupported format. – Hasan Zubairi Aug 07 '19 at 12:00
  • @HasanZubairi Are you able to show any of your client-side Angular code that's doing the uploading? JPEG images, as with nearly all image formats, are binary files and need to be sent with the correct MIME Content-Type, in this case `Content-Type: image/jpeg`. If you're uploading with some other MIME type, such as `Content-Type: text/x-json`, it could be getting corrupted in transit. – AlwaysLearning Aug 07 '19 at 13:10
0

It may be that our image was not saved successfully, such as the file stream is not completely copied.
We had better upload the image/stream by using Asynchronous programming model. Please refer to my service interface definition and implementation.
IService.cs

   [OperationContract]
    [WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json,BodyStyle =WebMessageBodyStyle.Wrapped)]
    Task UploadStream(Stream stream);

Service1.svc.cs

public async Task UploadStream(Stream stream)
{
    using (stream)
    {
        //save the image under the Uploads folder on the server-side(root directory).
        using (var file = File.Create(Path.Combine(HostingEnvironment.MapPath("~/Uploads"), Guid.NewGuid().ToString() + ".jpg")))
        {
            await stream.CopyToAsync(file);
        }
    }
}

Feel free to let me know if the problem still exists.

Updated.
Form Data is not supported by WCF built-in function. We should parse the stream to the practical file content.
Reading file input from a multipart/form-data POST
Please refer to my example (MultipartParser class is completed by others)
Service1.svc.cs

public async Task UploadStream(Stream stream)
{
    MultipartParser parser = new MultipartParser(stream);
    if (parser.Success)
    {
        using (var file = File.Create(Path.Combine(HostingEnvironment.MapPath("~/Uploads"), Guid.NewGuid().ToString() + ".png")))
        {
            await file.WriteAsync(parser.FileContents, 0, parser.FileContents.Length);
        }
    }
}

For CORS issue. Please add Global.aspx file to the WCF project.

protected void Application_BeginRequest(object sender, EventArgs e)
{
    HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
    if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
    {
        HttpContext.Current.Response.AddHeader("Cache-Control", "no-cache");
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With,Accept");
        HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
        HttpContext.Current.Response.End();
    }
}

Html.

<div class="form-group">
  <label for="file">Choose File</label>
  <input type="file"
         id="file"
         (change)="handleFileInput($event.target.files)">
   <input type="submit" id="mybutton" value="Upload" (click)="onSubmit();">      
</div>

App.component.ts

export class AppComponent {
  title = 'MyAngular20190808';
  fileToUpload: File = null;
  constructor(private http: HttpClient) {
  }
  handleFileInput(file: FileList) {
    this.fileToUpload=file.item(0);
  }

  onSubmit() {
    console.log('test');
    const formData = new FormData();
    formData.append('filekey', this.fileToUpload,this.fileToUpload.name);
    this.http.post('http://10.157.18.36:8800/service1.svc/UploadStream', formData, {responseType: 'text' })
      .subscribe(res => {
        console.log(res);

      })
  }
}

Feel free to let me know if there is anything I can help with.

Updated.
enter image description here

Abraham Qian
  • 7,117
  • 1
  • 8
  • 22
  • Thanks for your response. I copied your code into my service but when I am calling this method I am getting error 400 bad request. Any special webconfig setting for this code to work. Thanks – Hasan Zubairi Aug 07 '19 at 11:45
  • Which binding do you use? The above operation contract is applicable in webhttpbinding – Abraham Qian Aug 07 '19 at 12:00
  • @HasanZubairi Please check my updated reply. feel free to let me know if the problem still exist. – Abraham Qian Aug 08 '19 at 08:55
  • Now it is giving error 'Method not allowed'. In angular it is showing error 400 Bad request. – Hasan Zubairi Aug 08 '19 at 15:41
  • Before we construct the HTTP client to send the request, can we manage to upload the file successfully by using other tools, such as PostMan? I think we must ensure that the service works properly before we consume it. As before, we need to use Form to construct the HTTP request. – Abraham Qian Aug 09 '19 at 02:05
  • Please refer to my screenshot when I upload the file. – Abraham Qian Aug 09 '19 at 02:08