I want to fill data in excel and download that excel..
Following is the code..
public void DownloadExcel(int acid, int GroupId)
{
// Working Code
#region DownloadExcel
// string sConnectionString = ConfigurationManager.ConnectionStrings["TrainingMVCContext"].ConnectionString;
string sConnectionString = string.Empty;
LoginUserDetails objLoginUserDetails = (LoginUserDetails)InsiderTrading.Common.Common.GetSessionValue((string)ConstEnum.SessionValue.UserDetails);
sConnectionString = objLoginUserDetails.CompanyDBConnectionString;
SqlConnection con = new SqlConnection(sConnectionString);
SqlCommand cmd = new SqlCommand();
con.Open();
DataTable dt = new DataTable();
cmd = new SqlCommand("st_tra_NSEDownloadGroupWiseExcel", con);
cmd.Parameters.AddWithValue("#GroupId", GroupId);
cmd.CommandType = CommandType.StoredProcedure;
SqlDataAdapter adp = new SqlDataAdapter(cmd);
// ds = new DataSet();
adp.Fill(dt);
Microsoft.Office.Interop.Excel.Range oRng;
Microsoft.Office.Interop.Excel.Workbook mWorkBook;
Microsoft.Office.Interop.Excel.Sheets mWorkSheets;
Microsoft.Office.Interop.Excel.Worksheet mWSheet1;
Microsoft.Office.Interop.Excel.Application oXL;
object misValue = System.Reflection.Missing.Value;
string directory = ConfigurationManager.AppSettings["Document"];
string path = "Z:\\For Excel Demo\\Application\\InsiderTrading\\Document" + "\\" + "Stock Exchange Submission.xlsx";
oXL = new Microsoft.Office.Interop.Excel.Application();
oXL.Visible = true;
oXL.DisplayAlerts = false;
mWorkBook = oXL.Workbooks.Open(path, 0, false, 5, "", "", false, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "", true, false, 0, true, false, false);
mWorkSheets = mWorkBook.Worksheets;
mWSheet1 = (Microsoft.Office.Interop.Excel.Worksheet)mWorkSheets.get_Item("Sheet1");
Microsoft.Office.Interop.Excel.Range range = mWSheet1.UsedRange;
for (var row = 4; row <= dt.Rows.Count; row++)
{
for (var col = 0; col < dt.Columns.Count; col++)
{
mWSheet1.Cells[row + 1, col + 1].Value = dt.Rows[row - 1][col];
}
}
string Filename = "Testing.xlsx";
string pathTosave = (Path.Combine(directory, Filename));
mWorkBook.SaveAs(pathTosave);
using (var memoryStream = new MemoryStream())
{
HttpContext.Response.Clear();
HttpContext.Response.Charset = "";
HttpContext.Response.ContentType = "application/vnd.ms-excel";
HttpContext.Response.AddHeader("Content-Disposition", "inline;filename=" + pathTosave);
System.Text.StringBuilder strHTMLContent = new System.Text.StringBuilder();
//strHTMLContent.Append(LetterHTMLContent);
HttpContext.Response.Write(strHTMLContent);
HttpContext.Response.End();
HttpContext.Response.Flush();
}
mWorkBook.Close();
mWSheet1 = null;
mWorkBook = null;
oXL.Quit();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
#endregion DownloadExcel
}
but it gives the error For line
mWorkBook = oXL.Workbooks.Open(path, 0, false, 5, "", "", false, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "", true, false, 0, true, false, false);
error msg as follows--
An exception of type 'System.Runtime.InteropServices.COMException' occurred in InsiderTrading.dll but was not handled in user code
How can i do that..Plz help
Why dont you use a library, "LinqToExcell" to do all the plumbing?
https://www.codeproject.com/Articles/659643/Csharp-Query-Excel-and-CSV-Files-Using-LinqToExcel
Just upload the file using the following code in your controller. Note, you will need to save the file in your application because browsers do not allow you to access the location of your uploaded file (security purposes):
#region ImportExcell
public ActionResult ImportExcel()
{
return View();
}
[HttpPost]
public ActionResult ImportExcel(HttpPostedFileBase upload, FormCollection fc)
{
var v = System.Web.HttpContext.Current.Request.Files["upload"];
string contentType = upload.ContentType;
FileInfo fInfo = new FileInfo(upload.FileName);
//I am only allowing this kind of excel file. I got this from HttpPostedFileBase during debuging and checking content
if (!contentType.Contains(#"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"))
{
ModelState.AddModelError("", string.Format("This is not a valid file. This is '{0}'", contentType));
return View();
}
var fileName = upload.FileName;
//This is my temporary saving spot in my application
var filePathSaveTo = Server.MapPath(#"/Upload/ExcelFile");
string savedFileName = Path.Combine(filePathSaveTo, fileName);
//Now we need to save the file in a temp spot so we can access it later
upload.SaveAs(savedFileName);
try
{
string returnMsg = _fileDocDAL.LoadFromExcel(savedFileName);
ModelState.AddModelError("", string.Format("Done! " + returnMsg));
}
catch (Exception e)
{
string error = AliKuli.Utilities.ExceptionNS.ErrorMsgClass.GetInnerException(e);
ModelState.AddModelError("", string.Format(error));
}
return View();
}
#endregion
And your view....
#model ModelsClassLibrary.Models.Documents.FilesNS.FilesDocImportVM
#using (Html.BeginForm("ImportExcel", "FileDocs", null, FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="panel panel-info">
<div class="panel-heading">
Required Fields
</div>
<div class="panel-body">
<div class="form-group">
#Html.Label("Excel File", new { #class = "control-label col-md-2" })
<div class="col-md-10">
<input type="file" multiple="multiple" name="upload" id="front" />
</div>
</div>
<div class="form-group">
<div class="col-md-10">
<input type="submit" value="Upload" class="btn btn-success" /> |
#Html.ActionLink("Back to List", "Index")
</div>
</div>
</div>
</div>
</div>
}
My model is as below, but you need to make your model just like the data in the excel sheet. This is all explained in the documentation for LinqToExcell
namespace ModelsClassLibrary.Models.Documents.FilesNS
{
//[NotMapped]
public class FilesDocImportVM
{
public FilesDocImportVM()
{
FileId = -1;
}
#region Files
/// <summary>
/// The file number's ID
/// </summary>
public int FileId { get; set; }
/// <summary>
/// This is the file number that the user sees.
/// </summary>
public string FileNo { get; set; }
/// <summary>
/// This is the name of the file
/// </summary>
public string Description { get; set; }
/// <summary>
/// This is the parent's ID. 0 means no ID
/// </summary>
public int ParentId { get; set; }
#endregion
public int GetFileNumberFromOldFileNumber()
{
if (FileNo.IsNullOrEmpty() || FileId == -1 || Description.IsNullOrEmpty())
throw new Exception(string.Format("Proper Data not received. Record is {0}.FilesDocImportVM.GetFileNumberFromOldFileNumber ", this.ToString()));
return new FileDoc().GetFileNumberFromOldFileNumber(FileNo);
}
public void SelfErrorCheck()
{
if(FileId == -1 || FileNo.IsNullOrEmpty() || Description.IsNullOrEmpty())
throw new Exception(string.Format("Proper Data not received. Record is {0}. FilesDocImportVM.SelfErrorCheck", this.ToString()));
}
#region Category
/// <summary>
/// This is the categories ID
/// </summary>
public int CategoryId { get; set; }
/// <summary>
/// This is the name of the category
/// </summary>
public string CategoryName { get; set; }
#endregion
public override string ToString()
{
return string.Format("FileId: {0}, FileNo: {1}, Description: {2}, ParentId: {3}, CategoryId: {4}, CategoryName: {5}",
FileId,
FileNo,
Description,
ParentId,
CategoryId,
CategoryName);
}
}
}
The uploading code is pretty simple... this is the code that is used
public string LoadFromExcel(string excelFileName)
{
int noOfFiles = 0;
//*** NOTE - The line below is the code to import from Excel. I have wrapped it a bit to make it simple... the wrapper is below. The code after this line is just for fixing and checking the data.
var excelFile = AliKuli.Utilities.ExcellUtility.ImportFromExcelWithHeader(excelFileName, "AliKuliFiles");
if (excelFile.IsNullOrEmpty())
throw new Exception(string.Format("Utility Class failed to load. FileDocsDAL.LoadFromExcel"));
string totalFilesMsg = string.Format("Total Orignal Files: {0}", excelFile.Count());
var dataArray = excelFile.OrderBy(x => x.FileId).ToList();
if (dataArray.IsNullOrEmpty())
throw new Exception(string.Format("Data array failed to load. FileDocsDAL.LoadFromExcel"));
CheckTheData(dataArray);
//first make the categories
User theUser = Get_User();
string temp = "";
if (noOfFiles == 324)
temp = "Found";
CreateCategories(dataArray, theUser);
CreateAndSaveFile(ref noOfFiles, dataArray, theUser);
//now add the parents
SaveTheParents();
totalFilesMsg += " Counted: " + noOfFiles;
//CreateFileWithCategory(dataArray, admin);
return totalFilesMsg;
}
This is the wrapper code I wrote to wrap the LinqToExcel
public static class ExcellUtility
{
/// <summary>
/// This will read in the excel file such that it will stringify the cols of each row.
/// Example. If there are 3 cols, the the first 3 entries will be for col 0, then 1, then Col 2,
/// then... the 4th entry will again be col1
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
public static List<FilesDocImportVM> ImportFromExcelWithHeader(string excelFileName, string sheetName)
{
ExcelUtilityClass euc;
ExcelQueryFactory excel;
MakeExcelUtilityClass(excelFileName, out euc, out excel);
//This creates a IQueriable<FilesDocImportVM>
var data = from c in excel.Worksheet<FilesDocImportVM>(sheetName) select c;
var colNames = excel.GetColumnNames(sheetName).ToArray();
var datalist = data.ToList();
return datalist;
}
private static void MakeExcelUtilityClass(string excelFileName, out ExcelUtilityClass euc, out ExcelQueryFactory excel)
{
if (excelFileName.IsNullOrEmpty())
throw new Exception("No Excel File Name Passed");
euc = new ExcelUtilityClass();
excel = new ExcelQueryFactory(excelFileName);
}
}
}
Looks more complicated than it is... the uploading part was easy - just about one line of code after writing a the wrapper.
Good luck.
Related
I am trying to connect to SQL Server from the Web API and return a result set as JSON. But my code shown here is not working as expected. I am trying to return the entire query response as a JSON:
[HttpGet]
public HttpResponseMessage Getdetails(string ROOM)
{
string commandText = "SELECT * from [TDB].[dbo].[results_vw] where ROOM = #ROOM_Data";
string connStr = ConfigurationManager.ConnectionStrings["TDBConnection"].ConnectionString;
var jsonResult = new StringBuilder();
using (SqlConnection connection = new SqlConnection(connStr))
{
SqlCommand command = new SqlCommand(commandText, connection);
command.Parameters.Add("#ROOM_Data", SqlDbType.VarChar);
command.Parameters["#ROOM_Data"].Value = ROOM;
connection.Open();
var reader = command.ExecuteReader();
if (!reader.HasRows)
{
jsonResult.Append("[]");
}
else
{
while (reader.Read())
{
jsonResult.Append(reader.GetValue(0).ToString());
}
}
var response = new HttpResponseMessage(System.Net.HttpStatusCode.OK);
response.Content = new StringContent(jsonResult.ToString());
connection.Close();
return response;
}
}
This code returns this result:
333838362692368203368203368203362692368203359544362692368203362692368203362692368203368203
Where I am expecting the JSON as
{"data":
[
{"R_ID":"368203","ROOM":"K2"},
{"R_ID":"368203","ROOM":"K2"}
]}
Now I created a model class called DatabaseResult to store the response but I am not sure how I can store the result in to the model class in the controller
public class DatabaseResult
{
public int r_id { get; set; }
public string room { get; set; }
}
The current result is because you are only return the the value from the first column of each row and adding it to the string builder.
Create a new instance of the model and populate it using the values from the reader for each row.
[HttpGet]
public IHttpActionResult Getdetails(string ROOM) {
string commandText = "SELECT * from [TDB].[dbo].[results_vw] where ROOM = #ROOM_Data";
string connStr = ConfigurationManager.ConnectionStrings["TDBConnection"].ConnectionString;
var jsonResult = new StringBuilder();
using (SqlConnection connection = new SqlConnection(connStr)) {
using (SqlCommand command = new SqlCommand(commandText, connection)) {
command.Parameters.Add("#ROOM_Data", SqlDbType.VarChar);
command.Parameters["#ROOM_Data"].Value = ROOM;
connection.Open();
List<DatabaseResult> records = new List<DatabaseResult>();
using (var reader = command.ExecuteReader()) {
while (reader.Read()) {
var row = new DatabaseResult {
r_id = (int)reader["r_id"],
room = (string)reader["room"],
//...other properties.
};
records.Add(row);
}
return Ok(records);
}
}
}
}
The above uses the column names as the indexer to get the values from the reader.
I have a view, where I'm calling an ActionResult method, but putting a breakpoint in the method tells me it's not being called.
<div>
<ul class="list-group">
#foreach (var item in Model)
{
<li class="list-group-item">
<h4>Slide ID: #item.SlideId</h4>
<p><i>Received: #item.TimeStamp</i></p>
<div class="row">
<div class="col-md-4">
<h4>#Html.ActionLink("View details", "Well", new {slideid = item.SlideId})</h4>
<img src="#Url.Action("Index", "Images", new {id = item.SlideId})"/> //This is where I want to call the method
</div>
</div>
</li>
}
</ul>
And here's the method:
public class ImagesController : Controller
{
// GET: Images
public ActionResult Index(string id)
{
byte[] imageData = new byte[0];
string cs = "Data Source=" + "some path";
using (SQLiteConnection con = new SQLiteConnection(cs))
{
string stm = "SELECT LastImage FROM Well WHERE SlideId = " + "'" + id + "'";
con.Open();
using (SQLiteCommand cmd = new SQLiteCommand(stm, con))
{
using (SQLiteDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
imageData = Serialize(rdr["LastImage"]);
}
rdr.Close();
}
}
con.Close();
}
return File(imageData, "image/png");
}
public static byte[] Serialize(object obj)
{
var binaryFormatter = new BinaryFormatter();
var ms = new MemoryStream();
binaryFormatter.Serialize(ms, obj);
return ms.ToArray();
}
}
What I'm trying to achieve with this code is to load in an image from the database into the view. Any hints as to what I'm doing wrong?
Now with RouteConfig:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
When you write <img src="#Url.Action("Index", "Images", new {id = item.SlideId})"/> you don't call the action but the route url. The result is a string, for example localhost:8080/images/index/abcd123456 so, if you want to call the action, you need to use #Html.Action("Index", "Images", new {id = item.SlideId}). Note #Html.Action instead of #Url.Action
I think instead of opening and closing a db connection for each image, a better approach would be to gather all the information to render that page and send it in the model of the view you posted. Say it's called Index action of HomeController. It would look like something like this:
public class HomeController : Controller
{
public ActionResult Index(string id)
{
var listOfItems = new List<SomeClass>();
string cs = "Data Source=" + "some path";
using (SQLiteConnection con = new SQLiteConnection(cs))
{
string stm = "SELECT SlideId, TimeStamp, LastImage FROM Well";
con.Open();
using (SQLiteCommand cmd = new SQLiteCommand(stm, con))
{
using (SQLiteDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
var someItem = new SomeClass()
{
SlideId = rdr["SlideId"],
ImageData = Serialize(rdr["LastImage"]),
TimeStamp = rdr["TimeStamp"]
};
listOfItems.Add(someItem);
}
rdr.Close();
}
}
con.Close();
}
return View(listOfItems);
}
}
Of course if there are too many items you should always consider paging and limit the number of items in the list to cut down the response times.
I populate Dropdownlist from database and I want to show certain elements in red by setting their "class" attribute. So, I tried lots of ways and later I have created a custom HTML Helper for Dropdownlist. But it does not make any sense and although it seems to be added class attribute, this paramater cannot pass to Razor View from Controller. Could you help pls?
MyHelper.cs:
public static MvcHtmlString Custom_DropdownList(this HtmlHelper helper, string name, IEnumerable<SelectListItem> list, object htmlAttributes)
{
TagBuilder dropdown = new TagBuilder("select");
dropdown.Attributes.Add("name", name);
dropdown.Attributes.Add("id", name);
StringBuilder options = new StringBuilder();
foreach (var item in list)
{
options = options.Append("<option value='" + item.Value + "'>" + item.Text + "</option>");
}
dropdown.InnerHtml = options.ToString();
dropdown.MergeAttributes(new RouteValueDictionary(htmlAttributes));
return MvcHtmlString.Create(dropdown.ToString(TagRenderMode.Normal));
}
Controller:
private void PopulateMeetingsDropDownList(object selectedMeetings = null)
{
var meetingsQuery = repository.Meetings
.Join(repository.Cities, m => m.MeetingCityId, c => c.CityID,
(m, c) => new
{
CityID = c.CityID,
CityName = c.CityName,
MeetingDate = m.MeetingStartDate
}
)
.OrderBy(x => x.CityID)
.AsEnumerable()
.Select(
i => new
{
CityID = i.CityID,
Name = string.Format(
"{0} ({1:dd MMMM yyyy})",
i.CityName, i.MeetingDate),
Expired = i.MeetingDate < DateTime.UtcNow
}
).ToList();
var selectItems = new List<SelectListItem>(meetingsQuery.Count);
foreach (var record in meetingsQuery)
{
var item = new SelectListItem
{
Text = record.Name,
Value = record.Name
};
if (record.Expired)
{
item.Attributes.Add("class", "disabled"); //!!! Problem on this line
}
selectItems.Add(item);
}
ViewData["MeetingId"] = new SelectList(meetingsQuery, "CityID", "Name", selectedMeetings);
}
But after applying this method I got an error "'System.Web.Mvc.SelectListItem' does not contain a definition for 'Attributes' and no extension method 'Attributes' accepting a first argument of type...". So, I think I need to use another property or helper to assign class properties to custom racords (there is no problem filtering records on the "if (record.Expired)" line).
View:
#Html.Custom_DropdownList("MeetingId", ViewData["MeetingId"] as SelectList, new { id = "meetingId"})
Could you clarify me how to provide this? Thanks in advance.
Here is the modificated code for having ability for both Class and Disabled attributes:
Updated Code (for MyDropdownListFor):
Custom HTML Helper Class:
public static class MyHelpers
{
public class MySelectItem : SelectListItem
{
public string Class { get; set; }
public string Disabled { get; set; }
}
public static MvcHtmlString MyDropdownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IEnumerable<MySelectItem> list, string optionLabel, object htmlAttributes)
{
return MyDropdownList(htmlHelper, ExpressionHelper.GetExpressionText(expression), list, optionLabel, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
}
public static MvcHtmlString MyDropdownList(this HtmlHelper htmlHelper, string name, IEnumerable<MySelectItem> list, string optionLabel, IDictionary<string, object> htmlAttributes)
{
TagBuilder dropdown = new TagBuilder("select");
dropdown.Attributes.Add("name", name);
dropdown.Attributes.Add("id", name);
StringBuilder options = new StringBuilder();
// Make optionLabel the first item that gets rendered.
if (optionLabel != null)
options = options.Append("<option value='" + String.Empty + "'>" + optionLabel + "</option>");
foreach (var item in list)
{
if(item.Disabled == "disabled")
options = options.Append("<option value='" + item.Value + "' class='" + item.Class + "' disabled='" + item.Disabled + "'>" + item.Text + "</option>");
else
options = options.Append("<option value='" + item.Value + "' class='" + item.Class + "'>" + item.Text + "</option>");
}
dropdown.InnerHtml = options.ToString();
dropdown.MergeAttributes(new RouteValueDictionary(htmlAttributes));
return MvcHtmlString.Create(dropdown.ToString(TagRenderMode.Normal));
}
}
Controller:
private void PopulateMeetingsDropDownList(object selectedMeetings = null)
{
var meetingsQuery = repository.Meetings
.Join(repository.Cities, m => m.MeetingCityId, c => c.CityID,
(m, c) => new
{
CityID = c.CityID,
CityName = c.CityName,
MeetingDate = m.MeetingStartDate
}
)
.OrderBy(x => x.CityID)
.AsEnumerable()
.Select(
i => new
{
Value = i.CityID.ToString(),
DisplayValue = string.Format(
"{0} ({1:dd MMMM yyyy})",
i.CityName, i.MeetingDate),
Expired = i.MeetingDate < DateTime.UtcNow
}
).ToList();
var selectItems = new List<MyHelpers.MySelectItem>(meetingsQuery.Count);
foreach (var record in meetingsQuery)
{
var item = new MyHelpers.MySelectItem
{
Text = record.DisplayValue,
Value = record.Value
};
if (record.Expired)
{
item.Class = "disabled";
item.Disabled = "disabled";
}
selectItems.Add(item);
}
ViewBag.MeetingData = selectItems;
}
View:
<label>Meeting</label>
#Html.MyDropdownListFor(m => m.MeetingId, ViewBag.MeetingData as List<MyHelpers.MySelectItem>, "---- Select ----",
new { name = "meetingId", id = "meetingId"})
TL;DR; You are using SelectList, but you don't need to.
Create a new view model class, which you will pass to the view. It will contain all the properties you need, and may look like this:
Custom class to hold info about items:
public class CustomSelectItem
{
public string Text {get;set;}
public string Value {get;set;}
public string Class {get;set;}
public bool Selected {get;set;}
}
Since you are passing this data using ViewData, you don't have a limitation and you can put anything there. I advise that you use ViewBag instead of ViewData.
In your controller you can create a new List<CustomSelectItem> and pass it. When building the collection, if the item is expired just set the Class property to "disabled" or whatever you are using. Here is the code (I skipped the part where you get the meetings):
Controller:
var selectItems = new List<CustomSelectItem>(meetingsQuery.Count);
foreach (var record in meetingsQuery)
{
var item = new CustomSelectItem
{
Text = record.Name,
Value = record.Name
};
if (record.Expired)
{
item.Class = "disabled";
}
selectItems.Add(item);
}
ViewBag.MeetingData = selectItems;
Then modify the custom helper method you have created to accept a collection of CustomSelectItem instead of SelectListItem. You can write directly the HTML, because you have access to the Class property.
Custom helper method:
public static MvcHtmlString Custom_DropdownList(this HtmlHelper helper, string name, IList<CustomSelectItem> list, object htmlAttributes)
{
TagBuilder dropdown = new TagBuilder("select");
dropdown.Attributes.Add("name", name);
dropdown.Attributes.Add("id", name);
StringBuilder options = new StringBuilder();
foreach (var item in list)
{
options = options.Append("<option value='" + item.Value + "' class='" + item.Class + "'>" + item.Text + "</option>");
}
dropdown.InnerHtml = options.ToString();
dropdown.MergeAttributes(new RouteValueDictionary(htmlAttributes));
return MvcHtmlString.Create(dropdown.ToString(TagRenderMode.Normal));
}
Once this is done, you can invoke the helper from the view as follows:
View:
#Html.Custom_DropdownList("MeetingId", ViewBag.MeetingData as List<CustomListItem>, new { id = "meetingId"})
You can inherit the SelectList and add your own properties to the class, like this:
public class MySelectListItem : SelectListItem
{
public bool Highlighted { get; set; }
}
Once you have the custom class, you write your helper based on it. You can apply different css classes or change the style attribute.
public static class MyHtmlHelpers
{
public static MvcHtmlString DropDownListHighlighted(this HtmlHelper helper, string name, IEnumerable<MySelectListItem> itens)
{
StringBuilder dropDown = new St();
dropDown.AppendFormat("<select id='{0}' name='{0}'>", name);
foreach (var item in itens)
{
dropDown.AppendFormat("<option selected='{2}' value='{1}' class='{3}'>{0}</option>",
item.Text,
item.Value,
item.Selected ? "selected" : "",
item.Highlighted ? "highlighted" : "normal");
}
dropDown.Append("</select>");
return MvcHtmlString.Create(dropDown.ToString());
}
}
In your view (don't forget to add the namespace of your HTML helper class at the web.config or at the view):
#Html.DropDownListHighlighted("DropDown", ViewData["DropDownOptions"] as List<MySelectListItem>)
DropDownListHighlightedFor
You could do something like this to implementation a simple DropDownListHighlightedFor:
public static MvcHtmlString DropDownListHighlightedFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IEnumerable<MySelectListItem> itens)
{
return DropDownListHighlighted(htmlHelper, ExpressionHelper.GetExpressionText(expression), itens);
}
In the view:
#Html.DropDownListHighlightedFor(x => x.Option, ViewData["DropDownOptions"] as List<MySelectListItem>)
I have a fillable pdf. In which i have few textboxes.
I fill these fields by using following code(itextsharp).
DataTable dt = new DataTable();
String pdfPath1 = Server.MapPath("pdfs\\transmittal2.pdf");
if (File.Exists(pdfPath1))
{
dt = objClsTransmittal.GetTransmittal(jobid, cid);
String comment = "Correspondence generated for " + dt.Rows[0]["Recipient"].ToString();
var formfield = PDFHelper.GetFormFieldNames(pdfPath1);
formfield["DocDate"] = DateTime.Now.ToLongDateString();
formfield["Address1"] = dt.Rows[0]["Company"].ToString();
formfield["Address2"] = dt.Rows[0]["Address1"].ToString();
formfield["PropertyAddress"] = dt.Rows[0]["PropertyAddress"].ToString();
formfield["Job"] = dt.Rows[0]["JobID"].ToString();
formfield["Name"] = dt.Rows[0]["Recipient"].ToString();
formfield["CityStateZip"] = dt.Rows[0]["address2"].ToString();
formfield["E-mail"] = dt.Rows[0]["Email"].ToString();
var pdfcontent = PDFHelper.GeneratePDF(pdfPath1, formfield);
PDFHelper.ReturnPDF(pdfcontent, "Transmittal.pdf");
}
Currently its downloded as read only pdf.
when this pdf gets downloaded, i want that all fields still remain fillable, with the text i have filled in pdf. So that i can edit the text.
I'm looking forward for your replies.
Thanks.
EDIT
PdfHelper is my custom class. In which i have used following code:
using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Web;
using System.IO;
using iTextSharp.text.pdf;
public class PDFHelper
{
public static Dictionary<string, string> GetFormFieldNames(string pdfPath)
{
var fields = new Dictionary<string, string>();
var reader = new PdfReader(pdfPath);
foreach (DictionaryEntry entry in reader.AcroFields.Fields)
fields.Add(entry.Key.ToString(), string.Empty);
reader.Close();
return fields;
}
public static byte[] GeneratePDF(string pdfPath, Dictionary<string, string> formFieldMap)
{
var output = new MemoryStream();
var reader = new PdfReader(pdfPath);
var stamper = new PdfStamper(reader, output);
var formFields = stamper.AcroFields;
foreach (var fieldName in formFieldMap.Keys)
formFields.SetField(fieldName, formFieldMap[fieldName]);
stamper.FormFlattening = true;
stamper.Close();
reader.Close();
return output.ToArray();
}
public static string GetExportValue(AcroFields.Item item)
{
var valueDict = item.GetValue(0);
var appearanceDict = valueDict.GetAsDict(PdfName.AP);
if (appearanceDict != null)
{
var normalAppearances = appearanceDict.GetAsDict(PdfName.N);
if (normalAppearances != null)
{
foreach (var curKey in normalAppearances.Keys)
if (!PdfName.OFF.Equals(curKey))
return curKey.ToString().Substring(1); // string will have a leading '/' character, so remove it!
}
}
var curVal = valueDict.GetAsName(PdfName.AS);
if (curVal != null)
return curVal.ToString().Substring(1);
else
return string.Empty;
}
public static void ReturnPDF(byte[] contents)
{
ReturnPDF(contents, null);
}
public static void ReturnPDF(byte[] contents, string attachmentFilename)
{
var response = HttpContext.Current.Response;
if (!string.IsNullOrEmpty(attachmentFilename))
response.AddHeader("Content-Disposition", "attachment; filename=" + attachmentFilename);
response.ContentType = "application/pdf";
response.BinaryWrite(contents);
response.End();
}
Your code line
stamper.FormFlattening = true;
instructs iTextSharp to flatten the form fields, i.e. to integrate them into the page content and remove the form field annotations.
As you want to keep the form fields as editable fields, don't flatten the form.
Error: Cannot convert type in PDFHelper.cs
public static Dictionary<string, string> GetFormFieldNames(string pdfPath)
{
var fields = new Dictionary<string, string>();
var reader = new PdfReader(pdfPath);
foreach (DictionaryEntry entry in reader.AcroFields.Fields) //ERROR: 'System.Collections.Generic.KeyValuePair' to 'System.Collections.DictionaryEntry'
{
fields.Add(entry.Key.ToString(), string.Empty);
}
reader.Close();
return fields;
}
'System.Collections.Generic.KeyValuePair' to 'System.Collections.DictionaryEntry'
public class searchResult
{
public int id;
public string name;
}
/// <summary>
/// Summary description for WebService1
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ToolboxItem(false)]
[System.Web.Script.Services.GenerateScriptType(typeof(searchResult))]
// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
[System.Web.Script.Services.ScriptService]
public class WebService1 : System.Web.Services.WebService
{
[WebMethod]
public searchResult[] Search(int txtSearch)
{
//Semuler to slow internet connection
System.Threading.Thread.Sleep(2000);
//Declare collection of searchResult
List<searchResult> resultList = new List<searchResult>();
DataSet ds = Classes.getEmployeeDetailSet("SELECT [Employee ID],[First Name] FROM [Employee$] WHERE [Employee ID] like '" + txtSearch + "%'");
DataTable dt = new DataTable();
dt = ds.Tables[0];
if (dt.Rows.Count > 0)
{
searchResult result = new searchResult();
result.id = int.Parse(dt.Rows[0]["Employee ID"].ToString());
result.name = dt.Rows[0]["First Name"].ToString();
resultList.Add(result);
}
return resultList.ToArray();
}
i have created a list like
List<searchResult> resultList = new List<searchResult>(); this
and i have return that list
to call this i have use ajax code like this
$.ajax({ type: "POST",
url: "WebService1.asmx/Search", //function that in web service
data: "{txtSearch:" + $("#txtSearch").val() + "}", // passing value of txtSearch input
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(response) {
var result = response.d;
var value = '';
$.each(result, function(index, res) {
value = value + res.id + res.name;
});
alert(value);
alert("Record was updated successfully,,");
},
error: function(msg) {
alert("Error while calling web service,,");
}
});
My problem is that I am getting only one element from the database
I think I am not able to separate the list in the ajax response here
$.each(result, function(index, res) {
value = value + res.id + res.name;
});
I want to create a array with use of this id+name
please help
As Robert Slaney said, you are only returning the first result from the database.
Try something like this on the server side.
public class SearchResult
{
public int ID;
public string Name;
}
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ToolboxItem(false)]
[ScriptService]
public class WebService1 : System.Web.Services.WebService
{
[WebMethod, ScriptMethod]
public SearchResult[] Search(int employeeID)
{
List<SearchResult> resultList = new List<searchResult>();
DataSet ds = Classes.getEmployeeDetailSet("SELECT [Employee ID],[First Name] FROM [Employee$] WHERE [Employee ID] like '" + employeeID + "%'");
DataTable dt = ds.Tables[0];
foreach(DataRow row in dt.Rows)
{
resultList.Add(new SearchResult{ ID = int.Parse(row["Employee ID"].ToString()), Name = row["First Name"].ToString()});
}
return resultList.ToArray();
}
}
You can also use Chrome Developer Tools to inspect your request and response and verify that the data is actually being returned.