I'm doing some integration with a third party form builder software that allows the form to be posted to our own server. The form data and files are then saved to a DB. The issue is when the form contains multiple file upload fields, Request.Files is always empty.
Using Fiddler, I can see the binary files coming through. The only thing that I can think of is that the field name contains brackets in them (because it's being sent as an array) and so the model binder can't bind it properly? The field names that are coming through are tfa_20[0] and tfa_20[1].
Code-wise, it's pretty standard stuff:
var data = new Submission()
{
ConfigurationDetailId = configDetail.Id,
SubmitterEmail = submitterEmail,
SubmissionData = Request.Form.AllKeys.Select(k => new SubmissionData()
{
FieldName = k,
FieldValue = Request.Form[k]
}).ToList(),
SubmissionFiles = new List<SubmissionFile>()
};
// process any files uploaded
if (Request.Files.Count > 0)
{
foreach (string field in Request.Files)
{
var uploadedFile = Request.Files[field];
if (!string.IsNullOrEmpty(fileName))
{
data.SubmissionFiles.Add(GetSubmissionFile(uploadedFile, fileName));
}
}
}
Repository.SaveForm(data);
Any help would greatly be appreciated.
Use HttpPostedFileBase in order to get posted file to your action. in case of multiple files,should be used an HttpPostedFileBase[] array.
To Enable uploading in forms, is necessary to add enctype="multipart/form-data" to your form tag. or if you use razor syntax change your beginForm tag to this.
View.cshtml
#using (Html.BeginForm("action","controller", FormMethod.Post, new { #enctype =
"multipart/form-data" }))
{
}
public ActionResult YourAction(HttpPostedFileBase[] files)
{
var data = new Submission()
{
ConfigurationDetailId = configDetail.Id,
SubmitterEmail = submitterEmail,
SubmissionData = Request.Form.AllKeys.Select(k => new SubmissionData()
{
FieldName = k,
FieldValue = Request.Form[k]
}).ToList(),
SubmissionFiles = new List<SubmissionFile>()
};
if (files.Length > 0)
{
foreach (HttpPostedFileBase file in files)
{
var uploadedFile = file;
if (!string.IsNullOrEmpty(file.FileName))
{
data.SubmissionFiles.Add(GetSubmissionFile(uploadedFile, file.fileName));
}
}
}
return View();
}
Related
I´m working on a project that uses Caliburn micro in wpf C#.
I´m in the process that I want to rewrite my method ReadMediaFile() so it displays all files in a folder in a list.
My method looks lite this:
private void ReadMediaFile()
{
string result;
_movieviewmodel = new MoviesViewModel();
string[] filePaths = Directory.GetFiles(#"C:/Users/v80770/Desktop/Movies/");
foreach (var file in filePaths)
{
result = Path.GetFileName(file);
_movieviewmodel.MovieName = result;
}
AddItem(_movieviewmodel);
}
When I debug the program all the files show in filePaths but only one shows in my list.
The AddItem is located in a class called TreeViewBase (belongs to caliburn micro I think) and it looks like this:
public void AddItem(T item)
{
_dispatcher.SmartInvoke(() => Items.Add(item));
}
I got the movie files viewing in my list but my MediaUri binding in view is bind against a specific path file but I want it to change dependent on what I choose
I tried to edit the binding to this:
string test = _movieviewmodel.MovieName;
MediaUri = new Uri(test);
But only get a exception "System.UriFormatException: 'Invalid URI: The format of the URI could not be determined.'"
Picture of Uri
New Uri code:
_movieviewmodel.MovieFilePath = #"C:/Users/v80770/Desktop/Movies/";
string test = _movieviewmodel.MovieFilePath;
MediaUri = new Uri(test + _movieviewmodel.MovieName);
But it always shows the same movie and my _movieviewmodel.MovieName does not change name dependent which movie I choose, it always is the same movie.
The creation of a MoviesViewModel item object and AddItem(_movieviewmodel); must be inside foreach, otherwise it would add only the last item:
foreach (var file in filePaths)
{
var movieviewmodel = new MoviesViewModel();
movieviewmodel.MovieName = Path.GetFileName(file);
AddItem(movieviewmodel);
}
or
foreach (var file in filePaths)
{
AddItem(new MoviesViewModel
{
MovieName = Path.GetFileName(file)
});
}
This is the Json Format from the Imgur API using gallery search (heavily simplified, what matters is still there)
{
"data":[
{
"id":"q33FYFh",
"is_album":true,
"images":[
{
"id":"ObcYQRc",
"link":"https:\/\/i.imgur.com\/ObcYQRc.jpg",
"is_album":false
},
{
"id":"ifB0uac",
"link":"https:\/\/i.imgur.com\/ifB0uac.jpg",
"is_album":false
}
]
},
{
"id":"jYInL3c",
"is_album":true,
"images":[
{
"id":"bq2L5C4",
"link":"https:\/\/i.imgur.com\/bq2L5C4.jpg",
"is_album":false
},
{
"id":"Z0OPngk",
"link":"https:\/\/i.imgur.com\/Z0OPngk.jpg",
"is_album":false
}
]
},
{
"id":"8xxM5TO",
"link":"https:\/\/i.imgur.com\/8xxM5TO.jpg",
"is_album":false
}
],
"success":true,
"status":200
}
I need a way to get all image ID, not album ID, you can tell if an item is an album or a image by looking at the "is_album" tag
So first I tried to at least access the "id" subfield in the "images" field :
using Newtonsoft.Json;
string response = "Change this with the json file above"
dynamic dynJson = JsonConvert.DeserializeObject(response);
foreach (var data in dynJson)
{
string id = data["images"]["id"].ToString();
Debug.WriteLine(id);
}
This gave me this error : (By the way, I need to use Debug.WriteLine because Console doesn't work in PCL code in Xamarin.Forms)
System.InvalidOperationException: Cannot access child value on Newtonsoft.Json.Linq.JProperty.
But even if it worked, it would not get the id's for the images that are not part of an album.
using pseudo code this is what I would want (I think) :
for each (item in myjson)
{
if (item.is_album == "false")
{
Console.write(item.id);
}
else
{
for each (image in element)
{
Console.write(image.id);
}
}
}
You are not accessing your data correctly based on your JSON data.
data is your top level array, so your foreach would look like this:
foreach (var data in dynJson["data"])
Inside your foreach you would access your images like this:
string id = data["images"][0]["id"].ToString();
Where 0 is the index of the images array.
So combining this with another loop to get all the images for that data:
foreach (var data in dynJson["data"])
{
if (data["is_album"] == false)
{
// continue or do something
continue;
}
foreach(var image in data["images"])
{
string id = image["id"].ToString();
Debug.WriteLine(id);
}
}
You are accessing the dynamic object incorrectly. Here is the code you need:
public static List<string> GetImageIds(string jsonData)
{
List<string> imageIds = new List<string> ();
dynamic temp = JsonConvert.DeserializeObject (jsonData);
dynamic dynJson = temp.data;
foreach (dynamic data in dynJson)
{
int j = 0;
if (data.is_album == false)
{
imageIds.Add (data.id.ToString ());
}
else
{
dynamic images = data.images;
foreach (var image in images)
{
imageIds.Add (image.id.ToString ());
}
}
}
return imageIds;
}
Note: This is a simple example of how to traverse dynamic object. You will need to add validations and business logic to it as needed per your need.
Hope this helps!
Hello I try to download file from server.
Here is my controller
public ActionResult Downloads()
{
var dir = new System.IO.DirectoryInfo(Server.MapPath("~/Content/AnnFiles/"));
System.IO.FileInfo[] fileNames = dir.GetFiles("*.*"); List<string> items = new List<string>();
foreach (var file in fileNames)
{
items.Add(file.Name);
}
return View(items);
}
public FileResult Download(string file)
{
var FileVirtualPath = "~/Content/AnnFiles/" + file;
return File(FileVirtualPath, "application/force-download", Path.GetFileName(FileVirtualPath));
}
and in my view
#Html.ActionLink("Download", "Download", "announcement", new { id = Model.file})
It doesn't work. It returns the error
Could not find a part of the path 'C:\Myprojects\MyprojectName\MyprojectName\Content\AnnFiles\'
Any idea?
thank you
You need to use the following overload;
#Html.ActionLink("Download", "Download", "announcement", new { file = Model.file}, null);
Adding the null parameter at the end uses the following:
LinkExtensions.ActionLink Method (HtmlHelper, String, String, String, RouteValueDictionary, IDictionary)
Fiddle
Information given
I am using version 16.0.0.0 of the Microsoft.SharePoint.Client library.
There are several different document libraries in the SharePoint site. In code, we are given a list of document URLs (containing document GUIDs) and need to determine in which Document Library each is located, including the sub-folder if it is in a folder in the library.
Document Id (GUID) - gathered from document url query parameter "sourcedoc"
ex: "http://mycompany.sharepoint.com/spsite/_layouts/15/WopiFrame.aspx?action=default&file=testfile.docx&sourcedoc={6A290A65-4759-41ED-A13E-3333B45DF133}"
Information needed
Document Library Name
Document Library URL
Folder Name (if any)
Folder URL (if any)
Current Code
using SP = Microsoft.SharePoint.Client;
public class LibraryAndFolderInfo
{
public LibraryAndFolderInfo();
public string FolderName { get; set; }
public string FolderUrl { get; set; }
public string LibraryName { get; set; }
public string LibraryBaseUrl { get; set; }
}
public class SPDataAccess
{
public LibraryAndFolderInfo GetLibraryAndFolderInfo(Guid documentGuid)
{
SP.File file = Web.GetFileById(documentGuid);
Context.Load(file);
if (file != null)
{
Context.Load(file.ListItemAllFields);
Context.ExecuteQuery();
SP.ListItem item = file.ListItemAllFields;
Context.Load(item.ParentList);
Context.ExecuteQuery();
SP.List list = item.ParentList;
Context.Load(list);
Context.ExecuteQuery();
Context.Load(item.Folder);
Context.ExecuteQuery();
SP.Folder folder = item.Folder;
Context.Load(folder);
Context.ExecuteQuery();
LibraryAndFolderInfo lib = new LibraryAndFolderInfo();
lib.LibraryName = list.Title;
lib.LibraryBaseUrl = list.DefaultViewUrl;
lib.FolderName = folder.Name;
lib.FolderUrl = folder.ServerRelativeUrl;
return lib;
}
return null;
}
protected SP.ClientContext Context { get; set; }
}
The code currently fails at this line: Context.Load(item.ParentList); with the following error:
The property or field 'Title' has not been initialized. It has not been requested or the request has not been executed. It may need to be explicitly requested.
at Microsoft.SharePoint.Client.ClientObject.CheckUninitializedProperty(String propName)
at Microsoft.SharePoint.Client.List.get_Title()
at MyNamespace.SPDataAccess.GetLibraryAndFolderInfo(Guid documentGuid) in c:\path\SPDataAccess.cs:line 27
This line seems to be attempting to retrieve the Title of the list as it is being loaded and failing. Is this a correct assumption?
I am not super familiar with how exactly to load properties, so everything after the failing line is my best guess as to how it would work.
What is this code supposed to look like? Has anyone else tried to get this information from a document?
Below are provided some corrections, fixes and considerations for your code:
1)The condition if (file != null) is incorrect since it could not be used to determine whether file exists or not. The following example demonstrates how to verify whether file has been loaded:
SP.File file = Context.Web.GetFileById(documentGuid);
Context.Load(file);
Context.ExecuteQuery();
if (file.ServerObjectIsNull != null)
{
//File has been loaded..
}
2)item.Folder does not return parent Folder, it returns Folder associated with List Item and it is not the same
How to return parent Folder for a File?
var file = Context.Web.GetFileById(documentGuid);
Context.Load(file,i => i.ListItemAllFields);
Context.ExecuteQuery();
var folder = Context.Web.GetFolderByServerRelativeUrl((string)file.ListItemAllFields["FileDirRef"]);
Context.Load(folder);
Context.ExecuteQuery();
3)List.DefaultViewUrl returns a default view server relative url and it is not the same as List server relative url
How to retrieve List Url?
var file = Context.Web.GetFileById(documentGuid);
var item = file.ListItemAllFields;
Context.Load(item.ParentList, l => l.RootFolder);
Context.ExecuteQuery();
var listUrl = item.ParentList.RootFolder.ServerRelativeUrl;
4)Since SharePoint CSOM supports Request Batching there is no need to submit multiple queries, instead you could submit only a single query as demonstrated below:
SP.File file = Context.Web.GetFileById(documentGuid);
SP.ListItem item = file.ListItemAllFields;
var list = item.ParentList;
Context.Load(list, l => l.Title, l => l.RootFolder);
Context.Load(item);
Context.ExecuteQuery(); //<- submit a single batch query
Fixed example
public class SPDataAccess
{
public SPDataAccess(SP.ClientContext ctx)
{
Context = ctx;
}
public LibraryAndFolderInfo GetLibraryAndFolderInfo(Guid documentGuid)
{
var file = Context.Web.GetFileById(documentGuid);
var item = file.ListItemAllFields;
var list = item.ParentList;
Context.Load(list, l => l.Title, l => l.RootFolder);
Context.Load(item);
Context.ExecuteQuery();
var info = new LibraryAndFolderInfo();
var folderUrl = (string)item["FileDirRef"];
info.LibraryName = list.Title; //list title
info.LibraryBaseUrl = list.RootFolder.ServerRelativeUrl; //list url
if (folderUrl.Replace(list.RootFolder.ServerRelativeUrl, string.Empty).Length > 0)
{
info.FolderName = folderUrl.Split('/').Last(); //folder name
info.FolderUrl = folderUrl;
}
return info;
}
protected SP.ClientContext Context { get; private set; }
}
In my MVC(4) application, I'm fetching the image files from the local directory and displaying it in the browser.
I've a model to store the details,and a controller to get the files and a view to display them.
Model
public class ImageModel
{
List<string> _images = new List<string>();
public ImageModel()
{
_images = new List<string>();
}
public List<string> Images
{
get { return _images; }
set { _images = value; }
}
}
Controller
public ActionResult Index()
{
var imageFiles = new ImageModel();
imageFiles.Images.AddRange(Directory.GetFiles(#"c:\mypath"));
return View(imageFiles);
}
View
#for (int imgIndex = 0; imgIndex < Model.Images.Count; imgIndex++)
{
<div >
<img src = #Model.Images[imgIndex] alt="Image" />
</div>
}
But I can not view the images in the browser, its showing empty boxes with alt.
What did I miss here? Should I create a virtual directory instead of physical location.
First, local files require the file:// URI scheme. You seem to use the native file path as img src.
But the browser security model forbids the use of local source from inside a page served by a web server (http://, https:// protocols).
To fix your situation, the implement a controller that take the desired image file name as parameter, and serve its content using the File() action.
The problem is your path names. This might help:
Controller:
public ActionResult Index()
{
var imageFiles = new ImageModel();
imageFiles.Images.AddRange(System.IO.Directory.GetFiles(#"C:\wherever\files\are\"));
for (int i = 0; i < imageFiles.Images.Count; i++)
{
// get rid of the fully qualified path name
imageFiles.Images[i] = imageFiles.Images[i].Replace(#"C:\wherever\files\are\", "");
// change the slashes for web
imageFiles.Images[i] = imageFiles.Images[i].Replace('\\','/');
}
return View(imageFiles);
}
View:
#for (int imgIndex = 0; imgIndex < Model.Images.Count; imgIndex++)
{
<div >
<img src = "#Model.Images[imgIndex]" /> <!-- put the file in quotes -->
</div>
}
looking at the code snippet, it seems to me that you forgot to surround the path with quotes
<img src = "#Model.Images[imgIndex]" alt="Image" />
but looking at the overall code, i would recommend to use relative paths.
UPD:
For a more detailed explanation, i would recomentd this blog post