How to create a string for #Html.ActionLink that concatenates an integer from the Model and a string - model-view-controller

I'm using VS2015, MVC 5 design model. Creating a link that says "View" to open a PDF file in a new browser tab. It works fine, but the document sub-directory is hard-coded in the controller. I need to pass the document sub-directory + filename to the controller. The document sub-directory is the same as the Model.id . I'm having a difficult time converting the Model.id to a string and concatenating with the filename.
The following code in the view works fine with the hard-coded sub-directory in the controller
<td>#Html.ActionLink("View", "ViewAttachedDoc", "Documents", new { filename = item.filename}, new { target = "_blank" })</td>
But this code does not work
<td>#Html.ActionLink("View", "ViewAttachedDoc", "Documents", new { filename = Convert.ToString(Model.id) + "\" + item.filename }, new { target = "_blank" })</td>
The controller action is:
public FileResult ViewAttachedDoc(string filename)
{
string DocPath = ConfigurationManager.AppSettings["DocPath"];
string path = Path.Combine(DocPath, filename);
return File(path, "application/pdf");
}
TIA,
Tracy

The issue is likely from trying to pass a backslash through the URL. This link of a similar question has that same problem and their solution was to use HttpUtility.UrlEncode(value); and HttpUtility.UrlDecode(value);. Otherwise if that still doesn't work, what error are you getting?
P.S. C# automatically converts / -> \ for retrieving files.

Related

How to copy google doc to another folder in google drive service

I have a class that makes a copy of a google doc template file to then merge placeholders with data. The problem is that it's creating the copy in the same folder as the original template file and I can't find a way to copy it to another folder.
Say I have a structure like so in google drive.
Main
TemplateFiles
MainTemplateDoc
Contracts
CopyOfMainTemplateDocAfterBeingMerged
As you can see, the CopyOfMainTemplateDocAfterBeingMerged doc wouldn't be located in the TemplateFiles folder where the original template was, but copied to the Contracts folder.
Is it possible to use the google drive v2 service to move the file after creating the copy? I'm using the .net Google.Apis.Drive.v2 nuget package. Here's the code that I have so far to create the copy.
private string CopyDocument(string documentId, string title)
{
var newFile = new File { Title = title };
var documentCopyFile = driveService.Files.Copy(newFile, documentId).Execute();
return documentCopyFile.Id;
}
You are using Drive API v2.
You want to copy a file to the folder of Contracts.
You have already been able to use Drive API.
If my understanding is correct, how about this answer? Please think of this as just one of several possible answers.
In this answer, I would like to propose the following modification.
From:
var newFile = new File { Title = title };
To:
var newFile = new File {
Title = title,
Parents = new List<ParentReference> {new ParentReference {Id = parentId}}
};
or
var newFile = new File() {
Title = title
};
newFile.Parents = new List<ParentReference>() {new ParentReference() {Id = parentId}};
or
var newFile = new File();
newFile.Title = title;
newFile.Parents = new List<ParentReference>() {new ParentReference() {Id = parentId}};
parentId is the folder ID of the folder Contracts.
Note:
If you want to use Drive API v3, please use new List<string> {folderId} instead of new List<ParentReference> {new ParentReference {Id = folderId}}.
References:
Files: copy
Files: insert
If I misunderstood your question and this was not the direction you want, I apologize.

export chinese, japanese character in .csv file + mvc3

I am using following code to export the content to .cvs file
which also support chinese and japanese characters.
public ActionResult Download(strng accnumber)
{
string csvContent = "东西,东西,东西, hi";
var data = Encoding.UTF32.GetBytes(csvContent );
string filename = "CSV_" + accnumber + ".csv";
return File(data, "text/csv", filename);
}
when i export my file i am not getting proper chinese or japanese characters. what is missing?
i have used UTF32 encoding to support it.
Edited:
i have noticed that opening my .csv file in notepad shows perfect characters but ms-excel doesn't.
I am also got same problem, solve it by using UTF-8-BOM.
Encoding.UTF8.GetPreamble().Concat(Encoding.UTF8.GetBytes(stringData)).ToArray()
As you are on asp.net serving that file you also have to deal with the encoding of the http pipleline. I din't spot that earlier, sorry.
Instead of having a plain ActionResult you should use one of the derived ActionResults, I've used FileContentResult. Please pay note to the special ContentType I'm constructing to tell the browsers an UTF-32 file is coming...
public ActionResult Download(string accnumber)
{
string csvContent = "东西,东西,东西, hi";
var data = Encoding.UTF8.GetBytes(csvContent);
// add byte order mark
var bom = new byte[] { 0xEF, 0xBB, 0xBF };
// hold it all
var all = new byte[bom.Length + data.Length];
// copy over BOM
Array.Copy(bom, all, bom.Length);
// copy over data
Array.Copy(data, 0, all, bom.Length, data.Length);
string filename = "CSV_" + accnumber + ".csv";
var file = new FileContentResult( all, "text/csv" )
{
FileDownloadName = filename
};
return file;
}
I encountered this problem too. I fix it by adding the following line just before "return file ;" and it works for me.
Response.Write("<meta http-equiv=Content-Type content=text/html;charset=utf-8>");
return file;

URL.Action appends extra information to parameter

In my view, I have the following code:
#foreach (Document document in Model.Documents)
{
<img src="#Url.Action("GetDocument", new { docId = Model.DocId, filename =
document.DocumentName })" />
}
Stepping through the code, the filename resolves as expected, to "clown.jpg".
However, when this parameter is passed to the controller like so:
[AcceptVerbs(HttpVerbs.Get)]
[OutputCache(Duration = 36000)]
public virtual ImageResult GetDocument(int docId, string filename)
{
var attachment = _docService.GetDocument(docId, filename);
...........
}
The filename parameter has extra integers appended to it, so its value is something like "clown.jpg?316767349393".
Why is that, and how to I make it not do that? It is stopping me from looking up the file by filename. I could just hack my way around this by ignoring everything from the ? onward, but I want to know why this is happening and the correct method for stopping it from happening.
EDIT: I've worked around this by adding this line of code in the controller:
filename = filename.Split('?')[0];
But obviously that's not really how I want to be coding this...

Using MVC3 AJAX call to ActionResults fails when returning a File

I have an action result that returns a created File object (simplified for display!):
public ActionResult Create(int recID, int templateID)
{
//Get dbRecord from recID
DBRecord dbRecord = db.dbRecord.Find(recID);
//Get Template from templateID
Template template = db.Templates.Find(templateID);
if (template == null) throw new FileLoadException(string.Format("No database record found for template reference {0}",templateID));
//set fileOutput details
WordFile fileOutput = new WordFile(dbRecord, Server.MapPath("~/Documents/"),template);
//Create XML object for Template
XmlDocument xDoc = new XmlDocument();
//Save resulting document
xDoc.InnerXml = mergeData(template,dbRecord);
xDoc.Save(fileOutput.fullName);
if (!System.IO.File.Exists(fileOutput.fullName)) throw new FileNotFoundException(string.Format("File {0} could not be created", fileOutput.fileName));
//Return saved document
return File(fileOutput.fullName, "application/doc", fileOutput.fileName);
}
If I call this via an HTML RouteLink
<%: Html.RouteLink("Generate via HTML
, "GenerateDocument"
, new RouteValueDictionary(
new {
controller = "Template"
, action = "Create"
, recID = 1
,templateID = 1
}
)
)%>
Edit 1: It works fine, the document is generated and the user is prompted to open, save, etc. However, if I call it via an AJAX RouteLink, the code steps through, the document is created on the server, but the user is not prompted to open or save.
<%: Ajax.RouteLink("Generate via AJAX"
, "GenerateDocument"
, new RouteValueDictionary(
new {
controller = "Template"
, action = "Create"
, recID = 1
, templateID = 1 }
)
, new AjaxOptions
{
HttpMethod="POST"
, LoadingElementId="Refresh"
})%>
Is there an inherent restriction that prevents AJAX returning a file type or have I missed the right search combination to find an obvious answer?
I'm not sure I understand what you're talking about. Are you trying to return the file contents to a javascript variable? That is the only thing I can imagine an "AJAX RouteLink" would be good for. If you want it to prompt the user to open or save, use a normal link. If you're trying to embed the file in the page, don't return the file, return the html that you would use to do the embedding.

Getting a TinyMCE dropdown image list in an MVC3 application

I am trying to get an MVC3 app to feed TinyMCE with an external image list javascript file. I have TinyMCE set up so that if I use a static image list file, I get the image list, so I know that part works. But since I need to dynamically create the image list per user, I need something more flexible than a static file. It is down to providing the javascript from the following controller action:
public JavaScriptResult TinyMCEImageList(int id)
{
ListHelper lh = new ListHelper();
string js = "var tinyMCEImageList = new Array(\r\n" + "// Name, URL\r\n";
Dictionary<string, string> dict = lh.GetPetImageURLs(id);
int i = dict.Count();
foreach (var item in dict)
{
js += "['" + item.Key + "', '" + item.Value + "']";
if (i > 1)
{
js += ",\r\n";
}
i--;
}
js += "\r\n);";
return JavaScript(js);
}
The ListHelper.GetPetImageURLs() returns a dictionary object, which is simply a convenient way to hold the caption and URL of each image. When I call this controller from the browser, with the appropriate id parameter, I get what I would think is a workable JS file. In fact, such results are what I used to create the static file I used to test the TinyMCE image list setup, and that got me an actual dropdown image list.
Here is my TinyMCE setup. This is inside the view containing a TinyMCE instance:
tinyMCE.init({
mode: "textareas",
theme: "advanced",
plugins: "lists,pagebreak,style,table,inlinepopups,advhr,advimage,preview,searchreplace,print,paste,visualchars,nonbreaking",
theme_advanced_buttons1: "newdocument,|,bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,formatselect,fontselect,fontsizeselect",
theme_advanced_buttons2: "cut,copy,paste,pastetext,pasteword,|,search,replace,|,bullist,numlist,|,outdent,indent,blockquote,|,undo,redo,|,forecolor,backcolor,image",
theme_advanced_buttons3: "tablecontrols,|,visualaid,|,sub,sup,|,advhr,|,preview,print,|,visualchars,nonbreaking,template,blockquote,pagebreak",
theme_advanced_toolbar_location: "top",
theme_advanced_toolbar_align: "left",
theme_advanced_statusbar_location: "bottom",
theme_advanced_resizing: true,
external_image_list_url: "/InstructionDocument/TinyMCEImageList/#ViewBag.PetID"
});
The #ViewBag.PetID is being used elsewhere, so I know it is valid. Even if I hardcode this value, or specifically point to the controller action, I still do not get a dropdown list of images. I'm sure there's something simple I'm missing; can someone point out to me what it is (or at least give me some reasonable guidance)?
[EDIT]
The output from the TinyMCEImageList() action follows:
var tinyMCEImageList = new Array(
// Name, URL
['System Guinea Pig - 4', 'http://www.remindapet.com/Content/images/galler/1_4_970BB64F7C1A4375AF5722B8A62C8708.jpg'],
['System Guinea Pig - 5', 'http://www.remindapet.com/Content/images/gallery/1_4_CBA0D3DDBBED41C583A6E6C46FC9DADF.jpg']
);
Also, here are the headers for the above javascript return from the action:
Server ASP.NET Development Server/10.0.0.0
Date Fri, 23 Dec 2011 00:14:31 GMT
X-AspNet-Version 4.0.30319
X-AspNetMvc-Version 3.0
Cache-Control private
Content-Type application/x-javascript; charset=utf-8
Content-Length 292
Connection Close
So, the action really is returning a JavascriptResult. I just haven't been able to come up with how to get TinyMCE to see it.
Thanks!
Instead of rendering an javascriptresult, create a js file while you are rendering the page.
Controller
public ActionResult Index()
{
MakeJSFile();
return View();
}
MakeJSFile() function will create the jsfile we need, then the page will be rendered.
MakeJSFile() function
public void MakeJSFile()
{
#region declare
var imgPath = Server.MapPath("~/Content/images/gallery/");
var jsPath = Server.MapPath("~/Scripts/image_list.js");
List<string> fileList = populateList(imgPath, ".jpg");
#endregion
#region build jsfile
string content = "var tinyMCEImageList = new Array(";
foreach (var item in fileList)
{
content += "[\"" + item + "\", \"/Content/img/" + item + "\"]";
if (item != fileList.Last())
content += ",";
}
content += ");";
#endregion
#region create file
StreamWriter sw = new StreamWriter(jsPath, false);
sw.Write(content);
sw.Close();
#endregion
}
First declare the path for the directory where the images is, and also the path of the jsfile. Then create a list that contains the filenames and populate it(with populateList function).
Then create a string to build the jsfile.
After that create the file in you server.
You only need to do one more thing, create the populateList function.
PopulateList function
public List<string> populateList(string path, params string[] extensions)
{
List<string> list = new List<string>();
FileInfo fi = new FileInfo(path);
DirectoryInfo di = fi.Directory;
FileSystemInfo[] fsi = di.GetFiles();
foreach (FileSystemInfo info in fsi)
foreach (var ext in extensions)
if (info.Extension == ext)
list.Add(info.Name);
return list;
}
This function requires the path to the directory and file extensions.
If you want a specific list, just change this function.
One more thing, don't forget to change the value of external_image_list_url
tinyMCE.init({
...
external_image_list_url: "/Scripts/image_list.js"
});

Resources