I have seen many examples with ng-flow having the php side server to upload the files. But as I am not an expert in php and I need some help in the webapi, can someone please help me to find a working example or tutorial of ng-flow with webapi files upload.
Thanks everyone.
below is my web-api code to do this
[HttpPost]
public async Task<HttpResponseMessage> SaveFile()
{
if (!Request.Content.IsMimeMultipartContent())
Request.CreateResponse(HttpStatusCode.UnsupportedMediaType);
var provider = FileSaver.GetMultipartProvider();
var result = await Request.Content.ReadAsMultipartAsync(provider);
var fileInfo = FileSaver.MoveToTemp(result);
return Request.CreateResponse(HttpStatusCode.OK, fileInfo);
}
it uses the custom FileSaver class
public class FileSaver
{
public static MultipartFormDataStreamProvider GetMultipartProvider()
{
var uploadFolder = //your upload path;
return new MultipartFormDataStreamProvider(uploadFolder);
}
private static string GetDeserializedFileName(MultipartFileData fileData)
{
var fileName = GetFileName(fileData);
return JsonConvert.DeserializeObject(fileName).ToString();
}
private static string GetFileName(MultipartFileData fileData)
{
return fileData.Headers.ContentDisposition.FileName;
}
public static FileInfo MoveToTemp(MultipartFormDataStreamProvider result)
{
var originalFileName = GetDeserializedFileName(result.FileData.First());
var uploadedFileInfo = new FileInfo(result.FileData.First().LocalFileName);
string timestamp = DateTime.UtcNow.ToString("yyyyMMddHHmmssfff", CultureInfo.InvariantCulture);
var folder = Directory.CreateDirectory(**); //your upload path
if (!folder.Exists) folder.Create();
var filename = folder.FullName + #"\" + originalFileName;
MoveFile(uploadedFileInfo, filename);
return uploadedFileInfo;
}
private static void MoveFile(FileInfo fileInfo, string filename)
{
var count = 0;
do
{
try
{
fileInfo.MoveTo(filename);
return;
}
catch (Exception)
{
if (count == 4)
{
throw;
}
count++;
Thread.Sleep(1 * 1000);
}
} while (true);
}
}
Related
I'm building a desktop APP using windows forms that needs to be authenticated via a WebAPI using Token authentication.
The API is proved that work because a mobile APP is using it and also I can get results using POSTMAN
The problem is when I'm calling the Authentication method from the desktop App.
When I do the request, the API recieves it and it only goes until ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context), not reaching GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context) in the Auth process.
Here is my CustomAuthProvider
public class CustomOAuthProvider : OAuthAuthorizationServerProvider
{
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated();
return Task.FromResult<object>(null);
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var allowedOrigin = "*";
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { allowedOrigin });
var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password);
if (user == null)
{
context.SetError("invalid_grant", "El nombre de usuario o contraseƱa son incorrectos");
return;
}
ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager, "JWT");
var ticket = new AuthenticationTicket(oAuthIdentity, null);
context.Validated(ticket);
}
}
Here is my Startup class
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
HttpConfiguration httpConfig = new HttpConfiguration();
ConfigureOAuthTokenGeneration(app);
ConfigureOAuthTokenConsumption(app);
ConfigureWebApi(httpConfig);
}
}
At the moment I'm trying two different ways to authenticate the APP.
First One:
public LoginResponseModel Authenticate(LoginRequestModel applicationUser)
{
using (var client = new WebClient())
{
try
{
client.Headers["Content-Type"] = "application/json";
var data = applicationUser.Serialize();
var response = client.UploadString(Context.ApiUrl + "Authenticate","POST", JsonConvert.SerializeObject(applicationUser));
var resultJson = JsonConvert.DeserializeObject<LoginResponseModel>(response);
return resultJson;
}
catch (Exception exception)
{
}
}
return null;
}
And second one:
public async Task<ApplicationUser> Authenticate(LoginRequestModel applicationUser)
{
var client = new HttpClient();
try
{
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
var data = applicationUser.Serialize();
var response = await client.PostAsJsonAsync(Context.ApiUrl + "Authenticate",data );
// return null by default (test)
return null;
}
catch (Exception exception)
{
}
return null;
}
And this is the model I'm using for the request
public class LoginRequestModel
{
public string Grant_type { get; set; } = "Password";
public string UserName { get; set; }
public string Password { get; set; }
}
And this should be the response:
public class LoginResponseModel
{
public string Access_token { get; set; }
public string Token_type { get; set; }
public string Expires_in { get; set; }
}
Ah the moment both ways of calling the API only reach the initial verification of the owin process (ValidateClientAuthentication). What can be happening? How I can fix this? What I need to do to make the process go to GrantResourceOwnerCredentials?
thanks for the help
I solved my problem. The problem was that the form wasn't being filled and sent correctly.
private AuthToken GetAuthToken(LoginRequestModel applicationUser)
{
using (var client = new HttpClient())
{
var form = new Dictionary<string, string>
{
{"grant_type", "password"},
{"username", applicationUser.UserName},
{"password", applicationUser.Password},
};
try
{
var tokenResponse = client.PostAsync(Context.ApiUrl + "Authenticate", new FormUrlEncodedContent(form)).Result;
var token = tokenResponse.Content.ReadAsAsync<AuthToken>(new[] { new JsonMediaTypeFormatter() }).Result;
return token;
}
catch (Exception e)
{
Log4Net.log.Error("Error Getting Auth token", e);
return null;
}
}
}
I'm new to both react.js and ASP.Net core 2.0. And now writing a project using ASP.Net core 2.0 as back end API and react.js as application interface (front end). I'd like to know how to upload file. I have tried as follow but in the Back end side the parameter value (IFromFile file) is always null. And it seems that file was not posted correctly. Here are my codes:
.Net core (API)
[HttpPost]
[Route("upload")]
public async Task Upload(IFormFile file)
{
if (file == null) throw new Exception("File is null");
if (file.Length == 0) throw new Exception("File is empty");
using (Stream stream = file.OpenReadStream())
{
using (var binaryReader = new BinaryReader(stream))
{
var fileContent = binaryReader.ReadBytes((int)file.Length);
// await _uploadService.AddFile(fileContent, file.FileName, file.ContentType);
}
}
}
React.js
handleClick(event){
event.preventDefault();
// console.log("handleClick",event);
var self = this;
var apiBaseUrl = axios.defaults.baseURL + "user/upload";
if(this.state.filesToBeSent.length>0){
var filesArray = this.state.filesToBeSent;
const reader = new FileReader();
for(var i in filesArray){
//console.log("files",filesArray[i][0]);
var file = filesArray[i][0];
axios.post(apiBaseUrl, {data: file});
}
alert("File upload completed");
}
else{
alert("Please select files first");
}
}
Please advise how can I solve the issue.
I have done the job as follow:
at .Net core 2.0 web api
using Microsoft.AspNetCore.Http;
I created a model class
namespace Marter_MRM.Models
{
public class FileUploadViewModel
{
public IFormFile File { get; set; }
public string source { get; set; }
public long Size { get; set; }
public int Width { get; set; }
public int Height { get; set; }
public string Extension { get; set; }
}
}
And then I created a controller class and wrote the function as follow.
[HttpPost]
[Route("upload")]
public async Task<IActionResult> Upload(FileUploadViewModel model) {
var file = model.File;
if (file.Length > 0) {
string path = Path.Combine(_env.WebRootPath, "uploadFiles");
using (var fs = new FileStream(Path.Combine(path, file.FileName), FileMode.Create))
{
await file.CopyToAsync(fs);
}
model.source = $"/uploadFiles{file.FileName}";
model.Extension = Path.GetExtension(file.FileName).Substring(1);
}
return BadRequest();
}
And write api call function in react as follow:
handleUploadClick(event){
event.preventDefault();
var self = this;
var apiBaseUrl = axios.defaults.baseURL + "user/upload";
if(this.state.filesToBeSent.length>0){
var filesArray = this.state.filesToBeSent;
let f = new FormData();
for(var i in filesArray){
//console.log("files",filesArray[i][0]);
f = new FormData();
f.append("File",filesArray[i][0] )
axios.post(apiBaseUrl, f, {
headers: {'Content-Type': 'multipart/form-data'}
});
}
alert("File upload completed");
}
else{
alert("Please select files first");
}
}
It works perfect. Thanks!
This answer is true but I have problem with saving an image in my API so I change the method as you see and then work nice. You should set the parameter as [FromForm] in your API method
public async Task<IActionResult> Upload([FromForm]FileUploadViewModel model){...}
[Route("api/[controller]")]
[ApiController]
public class UploaderController : ControllerBase
{
[HttpPost]
public dynamic UploadJustFile(IFormCollection form)
{
try
{
foreach (var file in form.Files)
{
string path = Path.Combine(#"C:\uploadFiles");
using (var fs = new FileStream(Path.Combine(path, file.FileName), FileMode.Create))
{
file.CopyToAsync(fs);
}
UploadFile(file);
}
return new { Success = true };
}
catch (Exception ex)
{
return new { Success = false, ex.Message };
}
}
and in UI use this
uploadJustFile(e) {
e.preventDefault();
let state = this.state;
this.setState({
...state,
justFileServiceResponse: 'Please wait'
});
if (!state.hasOwnProperty('files')) {
this.setState({
...state,
justFileServiceResponse: 'First select a file!'
});
return;
}
let form = new FormData();
for (var index = 0; index < state.files.length; index++) {
var element = state.files[index];
form.append('file', element);
}
debugger;
axios.post('/api/uploader', form)
.then((result) => {
let message = "Success!"
if (!result.data.success) {
message = result.data.message;
}
this.setState({
...state,
justFileServiceResponse: message
});
})
.catch((ex) => {
console.error(ex);
});
}
In my case i simply missed to add multipart/form-data in my form.
If your controller is accepting uploaded files using IFormFile but you find that the value is always null, confirm that your HTML form is specifying an enctype value of multipart/form-data. If this attribute isn't set on the element, the file upload won't occur and any bound IFormFile arguments will be null.
Example:-
<form method="post" enctype="multipart/form-data" asp-controller="UploadFiles" asp-action="Index">
<div class="form-group">
<div class="col-md-10">
<p>Upload one or more files using this form:</p>
<input type="file" name="files" multiple />
</div>
</div>
<div class="form-group">
<div class="col-md-10">
<input type="submit" value="Upload" />
</div>
</div>
</form>
Remove the multiple attribute on this input element to allow just a single file to be uploaded.
I wanna achieve a simple task, which is to retrieve the binary image, and display it in my html
public class Artwork
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid artworkID { get; set; }
public string artworkName { get; set; }
public string artworkMimeType { get; set; }
public byte[] artworkMeta { get; set; }
public string artworkBase64String { get; set; }
}
Gets the artwork from DB
public Artwork GetArtwork(Guid id)
{
return _context.Artworks.SingleOrDefault(a => a.artworkID == id);
}
The API Controller
public IHttpActionResult Get(Guid id)
{
if (id == null)
{
return BadRequest();
}
var artwork = _repository.GetArtwork(id);
if (artwork == null)
return NotFound();
else
return Ok(artwork);
}
I've also used this method and it returns the data I want, but I still don't know how to use it to achieve my goal.
[HttpGet]
public HttpResponseMessage Get(Guid id)
{
HttpResponseMessage result = null;
try
{
var artwork = _repository.GetArtwork(id);
if (artwork == null)
{
result = Request.CreateResponse(HttpStatusCode.Gone);
}
else
{
// sendo file to client
byte[] bytes = artwork.artworkMeta ;
result = Request.CreateResponse(HttpStatusCode.OK);
result.Content = new ByteArrayContent(bytes);
result.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
result.Content.Headers.ContentDisposition.FileName = artwork.artworkName;
}
return result;
}
catch (Exception ex)
{
return Request.CreateResponse(HttpStatusCode.Gone);
}
}
And here's my angular request
$scope.getCity = function (id) {
$http.get('/api/artwork/' + $RouteParams.id).success(function (response) {
$scope.artwork= response;
//I've seen dudes using Blob here, but I'm not sure how that works
});
}
My problem is my angular request and my html, how do I display the artwork without doing this:
<img ng-src="data:{{artwork.artworkartworkMimeType}};base64,{{artwork.artworkBase64String}}" class="img-responsive" />
This displays the image, but I don't like how clumsy it looks, and I'm gonna be working with audio files as well, so I need a clean and understandable way. Please help!
As you said, this can be done by using a blob.
First step is to set the content type to application/octet-stream in the api method
[HttpGet]
public HttpResponseMessage Get(Guid id)
{
HttpResponseMessage result = null;
try
{
var artwork = _repository.GetArtwork(id);
if (artwork == null)
{
result = Request.CreateResponse(HttpStatusCode.Gone);
}
else
{
// sendo file to client
byte[] bytes = artwork.artworkMeta ;
result = Request.CreateResponse(HttpStatusCode.OK);
result.Content = new ByteArrayContent(bytes);
result.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
result.Content.Headers.ContentDisposition.FileName = artwork.artworkName;
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
}
return result;
}
catch (Exception ex)
{
return Request.CreateResponse(HttpStatusCode.Gone);
}
}
Then add the client request where you create a blob from the response. An url is then created for the blob which will be the source for the img
$scope.fileURL = '';
$http({
method: 'GET',
url: '/api/artwork/' + $RouteParams.id,
responseType: 'arraybuffer',
headers: {
'Access-Control-Allow-Origin': '*',
}
}).success(function (data, status, headers) {
headers = headers();
var contentType = headers['content-type'];
var blob = new Blob([data], { type: contentType });
//Create a url to the blob
$scope.fileURL = window.URL.createObjectURL(blob);
}).error(function (message) {
console.log(message);
});
Then bind url to the ngSrc
<img ng-src="{{fileURL}}" class="img-responsive" />
You could store image in binary format without encoding it to base64. Then it would be simpler to retrive image from DB.
In your asp controller:
[HttpGet]
public FileResult GetPhoto(int id) {
return File(_repository.GetArtwork(id).artworkMeta, "image/jpg");
}
And in angular view:
<img ng-src="/Home/GetPhoto/2" />
i want to check if some files exists in a folder on ftp then do specific task
i have the following methos for files check
public static bool CheckFileExistOnFTP(string ServerUri, string FTPUserName, string FTPPassword)
{
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(ServerUri);
request.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
request.Credentials = new NetworkCredential(FTPUserName, FTPPassword);
//request.Method = WebRequestMethods.Ftp.GetFileSize;
// request.Method = WebRequestMethods.Ftp.GetDateTimestamp;
try
{
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
return true;
}
catch (WebException ex)
{
FtpWebResponse response = (FtpWebResponse)ex.Response;
if (response.StatusCode == FtpStatusCode.ActionNotTakenFileUnavailable)
{
return false;
}
}
return true;
}
and i call that method on formload
if (FTPUtility.CheckFileExistOnFTP("ftp://ip address/Requests/", "edexcrawler", "edexcrawler123"))
{
btnUploadRequest.Visible = true;
btnUploadRequest.BackColor = System.Drawing.Color.LightGreen;
btnUploadRequest.ForeColor = System.Drawing.Color.Blue;
}
Based on your other question to get a list of files from ftp, you can check if the file you want to check is in that list:
Var fileNameToCkeck = "myfile.txt";
var utility= new FtpUtility();
utility.UserName = "...";
utility.Password = "...";
utility.Path = "...";
If (utility.ListFiles().Contains(fileNameToCkeck))
{
//The file exists
}
Or if you want to know if that path has any file:
If (utility.ListFiles().Count() > 0)
{
//The folder contains files
}
And here is the code for FtpUtility
public class FtpUtility
{
public string UserName { get; set; }
public string Password { get; set; }
public string Path { get; set; }
public List<string> ListFiles()
{
var request = (FtpWebRequest)WebRequest.Create(Path);
request.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
request.Credentials = new NetworkCredential(UserName, Password);
List<string> files = new List<string>();
using (var response = (FtpWebResponse)request.GetResponse())
{
using (var responseStream = response.GetResponseStream())
{
var reader = new StreamReader(responseStream);
while (!reader.EndOfStream)
{
var line = reader.ReadLine();
if (string.IsNullOrWhiteSpace(line) == false)
{
var fileName = line.Split(new[] { ' ', '\t' }).Last();
if (!fileName.StartsWith("."))
files.Add(fileName);
}
}
return files;
}
}
}
}
I want to pass three field in wwwform, which contain two single value and a json array.
Here is my Json:
{
"Fname":"Abc",
"Lname":"Xyz",
"Marks": [{"MarksA":"23","MarksB":"65" },
{"MarksA":"24","MarksB":"56" } ]
}
My current code is
void Start()
{
WWWForm form = new WWWForm();
form.AddField("Fname", "Abc");
form.AddField("Lname", "Xyz");
//passing the array as string
string Mymarks = "[{\"MarksA\":\"23\",\"MarksB\":\"65\" },{\"MarksA\":\"24\",\"MarksB\":\"56\" } ]";
form.AddField("Marks", Mymarks);
WWW www = new WWW("Urltoservice", form);
StartCoroutine("PostRequest", www);
}
IEnumerator PostRequest(WWW www)
{
yield return www;
if (www.error == null)
{
Debug.Log("Session Saved");
}
else
{
Debug.Log("WWW Error: " + www.error);
}
}
But I am getting 500 internal server Error. Please help me.
Try using WWW instead of WWWForm
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System.Collections.Generic;
public class SendData : MonoBehaviour {
void Start()
{
gameObject.GetComponent<Button>().onClick.AddListener(SendOnClick);
}
IEnumerator WaitForWWW(WWW www)
{
yield return www;
string txt = "";
if (string.IsNullOrEmpty(www.error))
txt = www.text; //text of success
else
txt = www.error; //error
GameObject.Find("TextDemo").GetComponent<Text>().text = "--------\n\n" + txt;
}
void SendOnClick()
{
try
{
GameObject.Find("TextDemo").GetComponent<Text>().text = "Starting..";
string ourPostData = "{\"MarksA\":\"23\",\"MarksB\":\"65\" },{\"MarksA\":\"24\",\"MarksB\":\"56\" }";
Dictionary<string,string> headers = new Dictionary<string, string>();
headers.Add("Content-Type", "application/json");
byte[] jData = System.Text.Encoding.ASCII.GetBytes(ourPostData.ToCharArray());
WWW api = new WWW("YOUR URL", jData, headers);
StartCoroutine(WaitForWWW(api));
}
catch (UnityException ex) { Debug.Log(ex.message); }
}
}