I can't seem to get this working with ng-file upload.
I need to pass in fine in my controller with bridge Id
The error I'm getting is:
"{"Message":"No HTTP resource was found that matches the request URI
'http://localhost/api/BridgeController/'.","MessageDetail":"No type was
found that matches the controller named 'BridgeController'."}"
Can't figure out why it can't find my method. Any ideas?
Here is my controller code that will get moved into a service
$scope.uploadFile = function (file) {
console.log("hitting file upload", $scope.selectedBridge);
if (file) {
debugger;
var request = {
method: 'POST',
url: '/api/Bridge/UploadBridgeImage',
data: angular.toJson($scope.selectedBridge.BridgeID),
file: file,
headers: { 'Content-Type': undefined }
};
Upload.upload(request).then(function (response) {
});
}
}
and back end C#
[HttpPost]
[Route("api/Bridge/UploadBridgeImage")]
public IHttpActionResult UploadBridgeImage()
{
try
{
var uploadedFiles = HttpContext.Current.Request.Files;
for (int i = 0; i < uploadedFiles.Count; i++)
{
var fileToSave = uploadedFiles[i];
var fileBytes = _iStremHelper.GetBytes(fileToSave.InputStream, fileToSave.ContentLength);
var file = BridgeFileEntity(fileBytes, fileToSave, 1);
using (_iFileRepository)
{
_iFileRepository.Save(file);
}
}
return Ok();
}
catch (Exception ex)
{
return InternalServerError();
}
}
Edited Code Here.
I was able to hit my break point in that post method in my C# controller. File have all the data I need. Now I need to get "data" some how. Any idea where is it located in context?
In order to get both file stream (in memory) and additional json data in web api controller you can define custom MultipartStreamProvider:
class MultipartFormDataInMemoryStreamProvider : MultipartFormDataRemoteStreamProvider
{
public override RemoteStreamInfo GetRemoteStream(HttpContent parent, HttpContentHeaders headers)
{
return new RemoteStreamInfo(new MemoryStream(), string.Empty, string.Empty);
}
}
Then use it in controller:
public async Task<IHttpActionResult> UploadBridgeImage()
{
var provider = await Request.Content.ReadAsMultipartAsync(new MultipartFormDataInMemoryStreamProvider());
foreach (var httpContent in provider.Contents)
{
if (!string.IsNullOrEmpty(httpContent.Headers.ContentDisposition?.FileName))
{
var byteArray = await httpContent.ReadAsByteArrayAsync();
//do whatever you need with byteArray
}
}
var bridgeId = provider.FormData["bridgeId"];
return Ok();
}
And on client side:
var request = {
url: '/api/Bridge/UploadBridgeImage',
data: {
file:file,
bridgeId:$scope.selectedBridge.BridgeID
}
};
Upload.upload(request).then(function (response) {
});
Related
I am using ASP.NET MVC Web calling with Twilio
Here is my Connect function
function callCustomer(phoneNumber) {
updateCallStatus("Calling " + phoneNumber + "...");
phoneNumber = phoneNumber.replace(/ /g, '');
var params = { To: phoneNumber };
Twilio.Device.connect(params);
}
Here is my Hangup function
function hangUp() {
Twilio.Device.disconnectAll();
}
Here is my TwiML Bin
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Dial callerId="++516xxx9999" record="record-from-answer">{{To}}</Dial>
</Response>
I am using Twilio client v1.6
//media.twiliocdn.com/sdk/js/client/v1.6/twilio.min.js
I want to collect complete information of each call as I connect to call or as I hang up the call like Call Duration, Call Sid, Record Sid, Call To, and other. Then with that information I would like implement play recorded call in my application.
I believe one way of doing it is set CALL STATUS CHANGES under Voice & Fax and receive all params.
This is how I ended up handling it.
/* Callback for when a call ends */
Twilio.Device.disconnect(function (connection) {
console.log(connection);
// Disable the hangup button and enable the call buttons
hangUpButton.prop("disabled", true);
callCustomerButtons.prop("disabled", false);
callSupportButton.prop("disabled", false);
updateCallStatus("Ready");
addCallLog(connection.parameters.CallSid);
});
addCallLog function
function addCallLog(id) {
var type = "";
var entityId = Number($("#Id").val());
$.ajax({
url: "/Phone/AddCallLog?callId=" + id,
type: "POST",
contentType: "application/json;",
success: function (data) {
// Handle Success Event
},
error: function (data) {
// Handle Error Event
}
});
}
Controller Method
[HttpPost]
public ActionResult AddCallLog(string callId,string type,int entityId)
{
TwilioClient.Init(_callSetting.Twilio.AccountSid, _callSetting.Twilio.Authtoken);
var records = CallResource.Read(parentCallSid: callId).ToList();
if (records.Any())
{
var callResource= records[0];
var parentRecord = CallResource.Fetch(pathSid: callId);
if (callResource.Status.ToString().Equals("completed", StringComparison.OrdinalIgnoreCase))
{
CallRecord callRecord = new CallRecord
{
EntityKey = entityId,
EntityType = type,
CallDateTimeUtc = callResource.DateCreated ?? DateTime.UtcNow,
CallSId = callResource.Sid,
ParentCallSId = callResource.ParentCallSid,
CalledById = _operatingUser.Id,
DurationInSeconds = parentRecord==null? Convert.ToDouble(callResource.Duration): Convert.ToDouble(parentRecord.Duration),
ToPhone = callResource.To,
CompanyId = _operatingUser.CompanyId
};
var callRecordResult= _callRecordService.Add(callRecord);
var recording = RecordingResource.Read(callSid: callId).ToList();
if (!recording.Any()) return Json(true);
foreach (RecordingResource recordingResource in recording)
{
using (var client = new WebClient())
{
var url =
"https://api.twilio.com" + recordingResource.Uri.Replace(".json", ".mp3");
var content = client.DownloadData(url);
CallRecordMedia callRecordMedia = new CallRecordMedia
{
CallRecordId = callRecordResult.Id,
ContentType = "audio/mpeg",
RecordingSId = recordingResource.Sid,
RecordingCallSId = recordingResource.CallSid,
FileType = "mp3",
Data = content,
Price = Convert.ToDouble(recordingResource.Price),
PriceUnit = recordingResource.PriceUnit,
DurationInSeconds = Convert.ToDouble(recordingResource.Duration)
};
_callRecordService.AddCallRecording(callRecordMedia);
}
}
}
}
return Json(true);
}
I have launched a new application at work. We create letters using OpenXML which works flawlessly on Dev, but on production the solution is not returning.
$("#createLetter").on("click", CreateLetter);
function CreateLetter() {
$.ajax({
type: "POST",
url: "/Letters/CreateLetter",
data: {
EntityType: "#overview.EntityType",
EntityId: #overview.EntityId,
Recipient: $("#Recipient").val(),
TemplatesLocation: $("#templatePath").val(),
SaveAs: $("#saveAs").val()
},
async: false,
success: openLetter
});
}
function openLetter(data) {
openFile(data);
window.location.reload(false);
}
Controller Method:
[ValidateInput(false)]
[HttpPost]
public JsonResult CreateLetter(CreateLetter input)
{
Recipient obj = logic.SplitRecipientInput(input.Recipient);
input.RecipientId = obj.RecipientId;
input.RecipientType = obj.Type;
input.Username = Helpers.GetLoggedInUser();
var x = logic.CreateLetter(input);
if (x.Success == 1)
{
return Json(x.Data, JsonRequestBehavior.AllowGet);
}
else
{
return Json("Error", JsonRequestBehavior.AllowGet);
}
}
Consumption Logic:
public CreatedLetter CreateLetter(CreateLetter input)
{
CreatedLetter response = new CreatedLetter();
Parameters.Add("TemplatePath", GetApiValue(input.TemplatesLocation));
Parameters.Add("EntityType", GetApiValue(input.EntityType));
Parameters.Add("EntityId", GetApiValue(input.EntityId));
Parameters.Add("RecipientId", GetApiValue(input.RecipientId));
Parameters.Add("RecipientType", GetApiValue(input.RecipientType));
Parameters.Add("Username", GetApiValue(input.Username));
Parameters.Add("SaveAs", GetApiValue(input.SaveAs));
response = Api.WebRequest<CreatedLetter>("CreateLetters", Parameters, Method.POST) as CreatedLetter;
return response;
}
API Controller method:
[ActionName("CreateLetter")]
[HttpPost]
public ApiResponse CreateLetter(LetterCreateInput input)
{
try
{
LetterTemplateLogic logic = new LetterTemplateLogic();
Random r = new Random();
var randomId = r.Next(100000, 999999);
string fileName = string.Format("{0} - {1}", randomId, input.SaveAs);
input.SaveAs = fileName;
// Get all objects for Letter
List<object> objs = logic.TemplateObjectsRetriever(input.EntityId, input.EntityType, input.Username, randomId);
objs.Add(logic.GetRecipient(input.RecipientId, input.RecipientType));
// Get save location
string saveLocation = logic.LetterLocationResolver(input.EntityId, input.EntityType);
var data = logic.OpenAndUpdateTemplate(objs, input.TemplatePath, input.SaveAs, saveLocation, FileExtension);
AttachmentInput letterAttachment = new AttachmentInput();
letterAttachment.Id = input.EntityId;
letterAttachment.FileTypeId = 1;
letterAttachment.Path = data;
letterAttachment.Username = input.Username;
letterAttachment.Description = fileName;
letterAttachment.EntityType = input.EntityType;
logic.InsertLetterAttachment(letterAttachment);
return ApiResponse.Return(data);
}
catch (Exception ex)
{
return ApiResponse.Error(ex);
}
}
This returns literally nothing on production. No errors in the console, no errors from the API which logs erroneous calls. I was hoping someone could make a suggestion?
Thanks.
I'm trying to send .csv file from my client app (angular 2) to my web api (ASP.NET), and I have done the following:
Tried to make FormData from my .csv file the following way:
public sendData() {
let formData = new FormData();
formData.append('file', this.file, this.file.name);
this.myService.postMyData(formData, this.name)
.subscribe(data => this.postData = JSON.stringify(data),
error => this.error = error,
() => console.log('Sent'));
}
Created a service on the client app where I'm sending this .csv file from.
postMyData(formData: any, name: string) {
this.s = <string><any>name;
const headers = new Headers();
headers.append('Content-Disposition', 'form-data');
const url: string = 'myUrl?methodName=' + name;
return this.http.post(url, formData, {headers: headers})
.map((res: Response) => res.json());
}
What's the problem now is that I don't know how to get that .csv file on the server. I tried it with the code found below, but I can't get the real content, I can only see the name, content type, length and stuff like that.
[HttpPost("GetMyCsvFile")]
public async Task<IActionResult> GetMyCsvFile(string name) {
var rawMessage = await Request.ReadFormAsync();
var msg = rawMessage.Files[0];
....
}
And then whatever I do with rawMessage, I can't get the content which I could read and do the stuff needed.
Is this possible to do?
You need to get the file and not the file name. Try this code, I'm getting a CSV file from my angular app.
public async Task<bool> GetFileFromAngular(IFormFile file) {
using (var reader = new StreamReader(file.OpenReadStream())) {
var config = new CsvConfiguration(CultureInfo.InvariantCulture) {
HasHeaderRecord = true,
MissingFieldFound = null,
BadDataFound = null,
TrimOptions = TrimOptions.Trim
};
using (var csv = new CsvReader(reader, config)) {
try {
var records = csv.GetRecords<DrugFormulary>().ToList();
var csvProcessor = new CsvProcessor(_dbContext, _configuration);
await csvProcessor.ProcessPlan(records);
} catch (System.Exception ex) {
throw ex;
}
}
}
return true;
}
I have these available APIs:
[HttpPost]
[CorsEnabled]
[ActionName("upstream")]
public DTO.Callback UploadPhoto(Stream data)
{
var m = new Logic.Components.User();
return m.UploadPhoto(data, Common.UserValues().Email);
}
[HttpPost]
[CorsEnabled]
[ActionName("upbyte")]
public DTO.Callback UploadPhoto(byte[] data)
{
var m = new Logic.Components.User();
return m.UploadPhoto(data, Common.UserValues().Email);
}
[HttpPost]
[CorsEnabled]
[ActionName("upfile")]
public DTO.Callback UploadPhoto(HttpPostedFileBase data)
{
var m = new Logic.Components.User();
return m.UploadPhoto(data, Common.UserValues().Email);
}
[HttpPost]
[CorsEnabled]
[ActionName("up")]
public DTO.Callback UploadPhoto(DTO.UserPhoto data)
{
var m = new Logic.Components.User();
return m.UploadPhoto(data, Common.UserValues().Email);
}
UserPhoto class
public class UserPhoto
{
public string Base64 { get; set; }
public byte[] Data { get; set; }
}
In the behind code, I try to convert or get the equivalent byte[] of each request data.
If I would get the correct Image byte, then I'm good to go.
In my PhoneGap application, I have these codes:
A function that opens the camera:
takePicture: function (success, error) {
var s = function (data) {
navigator.camera.cleanup();
(success || angular.noop)(data);
},
e = function (data) {
navigator.camera.cleanup();
(error || angular.noop)(data);
};
navigator.camera.getPicture(s, e,
{
quality: 100,
destinationType: Camera.DestinationType.FILE_URI,
sourceType: Camera.PictureSourceType.CAMERA,
encodingType: Camera.EncodingType.PNG,
correctOrientation: true
}
);
}
My first try is to convert the image to base64 string and use the 'up' API.
It works just fine for low quality not higher than 50. But the image becomes almost unrecognizable. So I set the quality to 100. And then the new problem comes, the phone hangs...
So I tried to use FileTransfer. Here is the code:
fileTransfer: function (filePath, serverUri, mimeType, params, success, error) {
var
u = $coreData.user.getSession()
;
var options = new FileUploadOptions();
options.fileKey = 'file';
options.mimeType = mimeType;
options.params = params;
options.chunkedMode = true;
options.headers = {
Connection: 'close',
Device: m.createDeviceHeader(),
'Authentication-Token': (u && u.SessionKey),
'Content-Type': 'application/json'
};
var ft = new FileTransfer();
ft.upload(filePath, encodeURI(serverUri), success, error, options);
}
Sample usage:
uploadFile: function (path) {
var def = $q.defer();
$coreUtility
.fileTransfer(path, $coreAPI.user.getUrl('upfile'), 'image/png', null,
function (success) {
def.resolve(m.callback(true, UPLOAD_PHOTO_SUCCESS, success));
},
function (error) {
def.reject(m.callback(false, UPLOAD_PHOTO_FAIL, error));
});
return def.promise;
}
But I was not able to upload the file, I always get not supported media type formatter and sometimes null reference exceptions. I'm totally out of idea.
Alright I get it now. For other struggling on the same problem, here is the solution.
[HttpPost]
[CorsEnabled]
[ActionName("upfile")]
public DTO.Callback UploadPhoto()
{
var m = new Logic.Components.User();
return m.UploadPhoto(HttpContext.Current.Request, Common.UserValues().Email);
}
Some logic:
public DTO.Callback UploadPhoto(HttpRequest req, string email)
{
if (req.Files.Count > 0)
{
var file = req.Files[0];
var m = new Logic.Components.User();
return m.UploadPhoto(file.InputStream, email);
}
return new DTO.Callback { Message = "Fail to upload. Make sure that you are uploading an image file." };
}
Some explanation about the solution:
The first part is your API, and the second part is the backend code.
To pass the image stream from PhoneGap to your ASP.Net MVC Web API, you will just have to use HttpContext.Current.Request to get the Stream from Phonegap.
Thanks in advance,
I need an MVC controller (=GetFreqSuggestions) that returns a JsonResult to feed the prefetch of a Typeahead javascript function.
$(function() {
var bestPictures = new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
prefetch:{
url: '../Reports/GetFreqSuggestions',
ttl:0
},
remote: '../Reports/ToDo?q=%QUERY'
});
bestPictures.initialize();
$('#remote .typeahead').typeahead({
hint: true,
highlight: true,
},
{
name: 'best-pictures',
displayKey: 'value',
source: bestPictures.ttAdapter()
});
});
The Json file is obtained from a azure blob storage as memorystream :
public async Task<bool> DownloadStreamFromBlobAsync(MemoryStream memStr, string blobContainerName, string blobName, ILogger log)
{
Stopwatch timespan = Stopwatch.StartNew();
try
{
CloudBlobContainer container = GetCloudBlob(blobContainerName);
if (container != null & memStr!=null)
{
CloudBlockBlob blockBlob = container.GetBlockBlobReference(blobName);
await blockBlob.DownloadToStreamAsync(memStr);
}
}
catch (Exception e)
{
log.Error(.....);
return false;
}
timespan.Stop();
log.TraceApi(.......);
return true;
}
In the controller I would like to convert the memorystream containing a pervious uploaded json file to a jsonresult.
public async Task<JsonResult> GetFreqSuggestions()
{
MemoryStream mem = await _suggestoinProvider.DownloadFrequentSuggestionsAsync();
if(mem != null)
{
return ????
}
return null;
}
All suggestions are welcome.
(I have tested with return Json(data, JsonRequestBehavior.AllowGet); that works perfectly when data was not a stream)
I do not prefer to save a Json file first on a server.
I think that either .ToArray() or .ReadToEnd() will do the trick here:
return Json(mem.ToArray(), JsonRequestBehavior.AllowGet);
or
return Json(mem.ReadToEnd(), JsonRequestBehavior.AllowGet);