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.
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);
}
As mentioned in my Title, upon accessing Request.Form.Files, the application throws the exception
System.Io.InvalidDataException: "Multipart body length limit 16384 exceeded" in an Asp.Net Core 2.0.0 Web Application. The Application I am working on is an Asp.Net Core MVC Web Application. I am using Summernote as my WYSIWYG Text-Editor. There I enabled the Feature to upload Images (s. my Javascript). This worked fine, until I needed to implement another uploader to upload text files like .pdf, txt, doc.
The Error appears while using the summernote texteditor, either with the "standard" upload button or a custom pdf uplader button (s. C# Code). The Image functionality worked fine, until I (tried) to implement the new pdf file uploader. At first my Error looked pretty basic because it was clear, that the files I tried to upload where bigger than 16kb (Asp.Net Cores Uploadlimit), so I tried the "common" methods (s. below) to fix this error, that are found on Stack Overflow and similar sites:
services.Configure<FormOptions>(x =>
{
x.ValueLengthLimit = int.MaxValue;
x.MultipartBodyLengthLimit = long.MaxValue;
x.MemoryBufferThreshold = 20;
});
or
public class RequestFormSizeLimitAttribute : Attribute, IAuthorizationFilter, IOrderedFilter
{
public int Order { get; }
private readonly FormOptions _formOptions;
public RequestFormSizeLimitAttribute(int valueCountLimit)
{
_formOptions = new FormOptions()
{
ValueCountLimit = valueCountLimit,
KeyLengthLimit = valueCountLimit
};
}
public void OnAuthorization(AuthorizationFilterContext context)
{
var features = context.HttpContext.Features;
var formFeature = features.Get<IFormFeature>();
if (formFeature == null || formFeature.Form == null)
{
// Request form has not been read yet, so set the limits
features.Set(new FormFeature(context.HttpContext.Request, _formOptions));
}
}
}
or
<system.web>
<httpRuntime maxRequestLength="1048576" />
</system.web>
<system.webServer>
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="1073741824" />
</requestFiltering>
</security>
</system.webServer>
however none of these Methods fixed my Error.
First of all my Jquery Code:
//For Image Uploading
function sendFiles(file) {
var data = new FormData();
data.append("file", file);
data.append('divisionId', $('#divisionId').val());
$.ajax({
data: data,
type: "POST",
url: "/api/File/UploadImageAjax",
cache: false,
contentType: false,
processData: false,
success: function (image) {
if (image !== "Error") {
var picture = $(image);
$('#summernote').summernote("insertNode", picture[0]);
} else {
bootbox.alert("Fehler beim hochladen des Bildes.");
}
}
});
}
//For PDF-File Upload
$('#btnUpload').on('click', function (e) {
var validation = validator.form();
e.preventDefault();
if (validation) {
var data = new FormData();
var text = document.getElementById('pdfText').value;
var fileSelect = document.getElementById('pdfFile');
data.append('linkName', text);
data.append('divisionId', $('#divisionId').val());
var files = fileSelect.files;
data.append('file', files[0]);
closeModal();
$.ajax({
data: data,
type: "POST",
url: "/api/File/UploadTextFileAjax",
cache: false,
contentType: false,
processData: false,
success: function (file) {
var atag = document.createElement('a');
atag.setAttribute('href', file.absoulutePath);
atag.setAttribute('id', file.fileId);
atag.innerHtml = file.linkText;
$('#summernote').summernote('insertNode', atag);
},
error: function(respons) {
bootbox.alert("Fehler beim Speichern der Text Datei.");
}
});
}
});
And finally my C# Code from the Controller:
[HttpPost]
[RequestFormSizeLimit(valueCountLimit: 2147483647)]
public async Task<IActionResult> UploadImageAjax()
{
//Exception thrown here.
var files = Request.Form.Files;
var request = Request.Form.FirstOrDefault(d => d.Key == "divisionId");
var divisionName = await GetDivisionNameAsync(request);
if (divisionName != null)
{
var user = await _userManager.GetUserAsync(HttpContext.User);
if (files.Count == 1 && user != null)
{
for (int i = 0; i < 1; i++)
{
var file = files[i];
if (TestImageFileName(file))
{
var path = ContentDispositionHeaderValue.Parse(file.ContentDisposition).FileName.ToString().Trim('"');
var fileName = $#"\images\Sportarten\{divisionName}\{path}";
if (!await _imageHandler.IsImageInDbAsync(fileName))
{
path = _hosting.WebRootPath + fileName;
using (FileStream fs = System.IO.File.Create(path))
{
await file.CopyToAsync(fs);
await fs.FlushAsync();
}
var image = new ImageViewModel { FileName = file.FileName, AbsolutePath = fileName, AspNetUserId = user.Id, FullPath = path };
var imageId = await _imageHandler.AddImageAsync(image);
var imageNode = $#"<img id='{imageId}' src='{fileName}' class='img-responsive'/>";
return Json(imageNode);
}
var id = await _imageHandler.GetImageIdbyNameAsync(path);
var node = $#"<img id='{id}' src='{fileName}' class='img-responsive'/>";
return Json(node);
}
}
}
}
return BadRequest("Error");
}
[HttpPost]
public async Task<IActionResult> UploadTextFileAjax()
{
//Exception thrown here.
var files = Request.Form.Files;
var request = Request.Form.FirstOrDefault(d => d.Key == "divisionId");
var divisionName = await GetDivisionNameAsync(request);
var linkText = Request.Form.FirstOrDefault(l => l.Key == "linkName").Value.ToString();
if (linkText != null && divisionName != null)
{
var user = await _userManager.GetUserAsync(HttpContext.User);
if (files.Count == 1 && user != null)
{
for (int i = 0; i < 1; i++)
{
var file = files[i];
if (TestTextFileName(file))
{
var path = ContentDispositionHeaderValue.Parse(file.ContentDisposition).FileName.ToString().Trim('"');
var fileName = $#"\files\Sportarten\{divisionName}\{path}";
if (await _file.IsFileInDb(fileName))
{
path = _hosting.WebRootPath + fileName;
using (FileStream fs = System.IO.File.Create(path))
{
await file.CopyToAsync(fs);
await fs.FlushAsync();
}
var textFile = new FileViewModel
{
AbsolutePath = fileName,
AspNetUserId = user.Id,
FileName = file.FileName,
FullPath = path
};
var fileId = await _file.AddFile(textFile);
return Ok(new {absolutePath = path, fileId = fileId, linkText = linkText});
}
var oldText = await _file.FindFilebyName(path);
return Ok(new { absolutePath = oldText.AbsolutePath, fileId = oldText.FileId, linkText = linkText });
}
}
}
}
return BadRequest("Error");
}
At last here is my Stacktrace I get, when the error is thrown(sorry for the bad quality):
Full Stacktrace of Error
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) {
});
In my MVC 4, the code below is not calling controller action when deployed to the server. but it is working on my local.
I am using IE 7.
THANKS IN ADVANCE.
js code:
$("#button").click(function () {
var uploadFile = document.getElementById("myFile").value;
var fullPath = document.getElementById('myFile').value;
var urlRegisterPartner = $('#registerurl').data('register-url');
if (fullPath) {
var startIndex = (fullPath.indexOf('\\') >= 0 ? fullPath.lastIndexOf('\\') : fullPath.lastIndexOf('/'));
var filename = fullPath.substring(startIndex);
if (filename.indexOf('\\') === 0 || filename.indexOf('/') === 0) {
filename = filename.substring(1);
}
$("#myModal").dialog("open");
$.get(urlRegisterPartner, { uploadFile: uploadFile }, function (data) {
alert(data.Messages);
$("#myModal").dialog("close");
});
}
else {
alert('Please select file to upload');
}
});
actionresult:
[HttpGet]
public JsonResult Upload(string uploadFile)
{
Message msg = new Message();
string fileLocation = Server.MapPath("~/UploadedFile/") + Path.GetFileName(uploadFile);
msg.Messages = uploadRepo.ReadFile(uploadFile, fileLocation);
return Json(msg, JsonRequestBehavior.AllowGet);
}
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.