I am doing Export to csv functionality in my MVC project. Currently if i write code on each page it works properly. but i want to avoid duplication of code doing export functionality centrally.
Here is my controller code
public ActionResult Export(string filterBy)
{
GridState gs = new GridState();
gs.Filter = filterBy;
gs.Page = 1;
gs.Size = int.MaxValue;
IEnumerable cities = City.GetAll().AsEnumerable().AsQueryable().ToGridModel(gs).Data;
MemoryStream output = new MemoryStream();
StreamWriter writer = new StreamWriter(output, Encoding.UTF8);
writer.Write("Country Name,");
writer.Write("State Name,");
writer.Write("City Name,");
writer.Write("City STD Code,");
writer.Write("Is Display");
writer.WriteLine();
foreach (CityViewModel city in cities)
{
writer.Write(city.CountryName);
writer.Write(",");
writer.Write("\"");
writer.Write(city.StateName);
writer.Write("\"");
writer.Write(",");
writer.Write("\"");
writer.Write(city.City.Name);
writer.Write("\"");
writer.Write(",");
writer.Write(city.City.STDCode);
writer.Write("\"");
writer.Write(",");
writer.Write(city.City.IsDisplay);
writer.WriteLine();
}
writer.Flush();
output.Position = 0;
return File(output, "text/comma-separated-values", "city.csv");
}
This is my View:
#model Telerik.Web.Mvc.GridModel<QuexstERP.BusinessCore.BusinessEntities.SysAdmin.CityViewModel>
#using Telerik.Web.Mvc.UI
#{
ViewBag.Title = "City List";
}
#(Html.Telerik().Grid(Model.Data)
.Name("Grid")
.DataKeys(keys => keys.Add(c => c.City.Id))
.ToolBar(commands => commands.Insert().ButtonType(GridButtonType.Image).ImageHtmlAttributes(new { style = "margin-left:0", title = "Add" }))
.ToolBar(commands => commands
.Custom()
.HtmlAttributes(new { id = "TestFilter", onclick = "command_onClick(this)" })
.Text("Export to csv")
.Action("Export", "City", new { filterBy = "~" }))
.DataBinding(dataBinding =>
dataBinding.Server()
.Select("Select", "City", new { GridButtonType.Text })
.Insert("Create", "City", new { GridButtonType.Text })
.Update("Save", "City", new { GridButtonType.Text })
.Delete("Delete", "City", new { GridButtonType.Text }))
.Columns(columns =>
{
columns.Command(commands =>
{
commands.Custom("Edit").Action("Edit", "City").ImageHtmlAttributes(new { #class = "t-edit" }).ButtonType(GridButtonType.Image).HtmlAttributes(new { title = "Edit", #class = "RightAlign" });
}).Width(40).Title("Edit").Visible(OperationHelper.EditOperation);
columns.Command(commands =>
{
commands.Delete().ButtonType(GridButtonType.Image).HtmlAttributes(new { title = "Delete", #class = "RightAlign" });
}).Width(40).Title("Delete").Visible(OperationHelper.DeleteOperation);
columns.Bound(p => p.CountryName).Width(200).Title("Country");
columns.Bound(p => p.StateName).Width(200).Title("State");
columns.Bound(p => p.City.Name).Width(310).Title("City");
columns.Bound(p => p.City.STDCode).Width(200).Title("STD Code");
columns.Bound(p => p.City.IsDisplay).Width(110).Title("IsDisplay");
})
.Pageable()
.Scrollable()
.Sortable()
.Filterable()
.Resizable(command => command.Columns(true))
)
#section HeadContent {
<script type="text/javascript">
function command_onClick(e) {
var grid = $('#Grid').data('tGrid');
var $cmd = $('#TestFilter');
// Get its 'href' attribute - the URL where it would navigate to
var href = $cmd.attr('href');
// Update the 'filter' parameter with the grids' current filtering state
href = href.replace(/filterBy=(.*)/, 'filterBy=' + (grid.filterBy || '~'));
// Update the 'order' parameter with the grids' current ordering state
href = href.replace(/orderBy=([^&]*)/, 'orderBy=' + (grid.orderBy || '~'));
// Update the 'page' parameter with the grids' current page
href = href.replace(/page=([^&]*)/, 'page=' + grid.currentPage);
// Update the 'href' attribute
$cmd.attr('href', href);
}
</script>
}
I want to do Export to CSV centrally. as many of the form like state, country and country in my project have the exporting functionality. is it possible to write one generic class and pass parameter to it. and export to csv is done centrally???
We achieved something similar to this by binding datasources to a GridView within a controller method e.g.
var data = GetSomeData();
var grid = new GridView { DataSource = data };
grid.DataBind();
Response.ClearContent();
Response.AddHeader("content-disposition", "attachment; filename=MyExcel.xls");
Response.ContentType = "application/vnd.ms-excel";
var sw = new StringWriter();
var htw = new HtmlTextWriter(sw);
grid.RenderControl(htw);
Response.Write(sw.ToString());
Response.End();
This way you can just set the relevant datasource on the GridView and return a dump of the grid data in the output stream. With a bit of refactoring we were able to make this generic and it is now used by all of our UI grids for exporting to Excel/CSV.
Just for the reference. Don't bind data to the grid and then export it to excel. It will give you
the file you are trying to open is in a different format than
specified by the file extension
Error when you try to open Excel.
I have done this solution for above problem
public static void ExportToExcel(IEnumerable<dynamic> data, string sheetName)
{
XLWorkbook wb = new XLWorkbook();
var ws = wb.Worksheets.Add(sheetName);
ws.Cell(2, 1).InsertTable(data);
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
HttpContext.Current.Response.AddHeader("content-disposition", String.Format(#"attachment;filename={0}.xlsx",sheetName.Replace(" ","_")));
using (MemoryStream memoryStream = new MemoryStream())
{
wb.SaveAs(memoryStream);
memoryStream.WriteTo(HttpContext.Current.Response.OutputStream);
memoryStream.Close();
}
HttpContext.Current.Response.End();
}
It get data dynamically. use ClosedXml so no error and the Export to Excel functionality is central in application
Hope this will help someone. :)
Related
I have been looking around the Telerik forums & Stackoverflow for an answer for this and I am completely stuck and unable to figure out the issue.
I am using the Kendo UI for Asp.Net Core Scheduler Control. I have it reading the data from my controller fine. However, I cannot get it call the HttpPut handler correctly.
When checking the traffic I get the following response, and therefor my breakpoint inside my HttpPut handler will never be hit.
400 - Bad Request
{"":["The input was not valid."]}
My code in my view is:
#(Html.Kendo().Scheduler<MeetingViewModel>()
.Name("SchedulerView")
.Height(500)
.Date(DateTime.Now.ToUniversalTime())
.StartTime(new DateTime(2018, 11, 28, 0, 00, 00).ToUniversalTime())
.MajorTick(30)
.ShowWorkHours(false)
.Footer(false)
.Editable(edit =>
{
//edit.Resize(false);
edit.Create(false);
})
.Views(views =>
{
views.TimelineView(timeline => timeline.EventHeight(50));
//views.TimelineWeekView(timeline => timeline.EventHeight(50));
//views.TimelineWorkWeekView(timeline => timeline.EventHeight(50));
//views.TimelineMonthView(timeline =>
//{
// timeline.StartTime(DateTime.Now);
// timeline.EndTime(DateTime.Now.AddMonths(1));
// timeline.MajorTick(1440);
// timeline.EventHeight(50);
//});
})
.Timezone("Etc/UTC")
.Group(group => group.Resources("WorkCenters" /*,"Attendees"*/).Orientation(SchedulerGroupOrientation.Vertical))
.Resources(resource =>
{
resource.Add(m => m.ScheduleRowID)
.Title("Work Center")
.Name("WorkCenters")
.DataTextField("Text")
.DataValueField("Value")
.DataColorField("Color")
.BindTo(#Model.AvailableWorkCenters);
})
.DataSource(d => d
.ServerOperation(true)
.WebApi()
.Model(m =>
{
m.Id(f => f.ActivityID);
m.Field(f => f.Title).DefaultValue("No title");
//m.RecurrenceId(f => f.RecurrenceID);
m.Field(f => f.Description).DefaultValue("No Description");
})
.Events(events => events.Error("error_handler"))
.Read(read => read.Action("GetActivities", "Scheduler").Data("setRequestDateTimes"))
//.Create(create => create.Action("Post", "Scheduler"))
.Update(update => update.Action("PutActivity", "Scheduler", new { id = "{0}" }).Type(HttpVerbs.Put))
//.Destroy(destroy => destroy.Action("Delete", "Scheduler", new { id = "{0}" }))
)))
And my API Controller is as follows:
[Route("Api/[controller]")]
[ApiController]
public class SchedulerController : DawnController
{
public SchedulerController(DatabaseContext context) : base(context)
{
}
[HttpGet]
public DataSourceResult GetActivities([DataSourceRequest] DataSourceRequest request, DateTime requestStartDateTime, DateTime requestEndDateTime)
{
//Kendo doesnt seem to send the full date range. so + 1 day to end
requestEndDateTime = requestEndDateTime.AddDays(1);
List<MeetingViewModel> test = new List<MeetingViewModel>();
foreach (JobTask jobTask in Context.JobTask)
{
if (JobTask.HasActivityInDateRange(jobTask, requestStartDateTime, requestEndDateTime))
{
foreach (Activites jobTaskAct in jobTask.Activites)
{
test.Add(new MeetingViewModel()
{
JobTaskID = jobTask.JobTaskId,
ActivityID = jobTaskAct.ActivityId,
Title = jobTaskAct.Name,
Description = jobTaskAct.Description,
Start = jobTaskAct.StartTime.ToUniversalTime(),
End = jobTaskAct.EndTime.ToUniversalTime(),
IsAllDay = false,
ScheduleRowID = jobTaskAct.Workcenter.WorkCenterId,
});
}
}
}
return test.ToDataSourceResult(request);
}
[HttpPut("{id}")]
public IActionResult PutActivity(int id, MeetingViewModel task)
{
if (ModelState.IsValid && id == task.ActivityID)
{
try
{
//breakpoint here
bool a = true;
//update the db here
}
catch (DbUpdateConcurrencyException)
{
return new NotFoundResult();
}
return new StatusCodeResult(200);
}
else
{
return BadRequest(ModelState.Values.SelectMany(v => v.Errors).Select(error => error.ErrorMessage));
}
}
}
Thanks
The URL exposing your controller method PutActivity in your controller example is PUT api/scheduler/{id}
To access that URL use this Update method.
.Update(update => update.Action("Put", "Scheduler", new { id = "{0}" }))
See this demo as example
Alternatively
If you want to implment the URL api/Scheduler/PutActivity/{id} (similar pattern to your GET) then you will need to modify the attribute over the put method as follows.
[HttpPut("PutActivity/{id}")]
public IActionResult PutActivity(int id, MeetingViewModel task)
Then you can call api/Scheduler/PutActivity/{id} with this asp.net action call.
.Update(update => update.Action("PutActivity", "Scheduler", new { id = "{0}" }).Type(HttpVerbs.Put))
Data is not binding to Kendo dropdown list list is returning form my method
My dropdown
#(Html.Kendo().DropDownListFor(model => model.ParentAssetID)
.OptionLabel(" ")
.Name("ParentAssetID")
.DataTextField("AssetName")
.DataValueField("AssetId")
.SelectedIndex(0)
.Text(string.Empty)
.DataSource(source =>
{
source.Read(read =>
{
read.Url("../Asset/GetAllAssetsByCompanyId");
});
}))
my Action Result
public IEnumerable<AssetDetails> GetAllAssetsByCompanyId()
{
IList<AssetDetails> _assetSearchlist;
using (var client = new HttpClient())
{
AssetRepository assetrep = new AssetRepository();
Guid cp = new Guid(Session["CurrentCompanyId"].ToString());
_assetSearchlist = assetrep.GetAllAssetsByCompanyId(cp, "", "", "");
return _assetSearchlist;
}
}
public JsonResult GetOpportunityListByAccount(string Id)
{
Guid ID = new Guid(Id);
List<OpportunityViewModel> cpvm = new List<OpportunityViewModel>();
List<CrmOpportunity> crmOppList = new List<CrmOpportunity>();
cpvm = srv.OpportunitySet.Where(z => z.CustomerId.Id == ID).ToList();
foreach (var crm in cpvm )
{
CrmOpportunity crmOpp = new CrmOpportunity();
crmOpp.Id = crm.Id;
crmOpp.Name = crm.Name;
crmOppList.Add(crmOpp);
}
return Json(crmOppList, JsonRequestBehavior.AllowGet);
}
#(Html.Kendo().DropDownListFor(x => x.FromOpportunity)
.Name("OpportunityDDL")
.DataTextField("Name")
.DataValueField("Id")
.DataSource(source => {
source.Read(read =>
{
read.Action("GetOpportunityListByAccount", "CrmIntegration");
})
. ServerFiltering(true);
})
.HtmlAttributes( new { style = "margin-left:13px; width: 275px;" })
)
Data access is a little truncated but this is what you'll need to do
#(Html.Kendo().DropDownListFor(model => model.ParentAssetID)
.OptionLabel(" ")
.Name("ParentAssetID")
.DataTextField("AssetName")
.DataValueField("AssetId")
.SelectedIndex(0)
.Text(string.Empty)
.DataSource(source =>
{
source.Read(read =>
{
read.Action("GetAllAssetsByCompanyId", "Asset");
});
}))
Only a minor change but have you tried read.Action? Also is maybe try removing the following;
DropDownListFor(model => model.ParentAssetID)
and replace with
DropDownListFor<ClassName>()
Only a thought.
i'm using kendo ui in my asp.net mvc 4 with razor views and encounter problem with kendo combo when the list load from an action via ajax with sending parameters to the server like the sample here:HERE
becuase the table has more then 2,000 rows.
when i load the edit page, the combo load and filter the data as expected, but the value of this field is - [object object].
i did declare the .DataTextField("ProffName") + .DataValueField("ID")
My ClientsController:
public ActionResult Edit(int id = 0)
{
Clients clients = db.Clients.Find(id);
if (clients == null)
{
return HttpNotFound();
}
ViewData["MyAgency"] = new SelectList(db.Agency, "ID", "AgentName", clients.AgencyId);
ViewData["MyCategory1"] = new SelectList(db.CategoryTbl, "ID", "category", clients.CategoryId);
List<SelectListItem> obj = new List<SelectListItem>();
obj.Add(new SelectListItem { Text = "male", Value = "1" });
obj.Add(new SelectListItem { Text = "female", Value = "2" });
obj.Add(new SelectListItem { Text = "choose", Value = "0" });
ViewData["MyMin"] = obj;
ViewBag.ProffID = new SelectList(db.ProfTBL, "ID", "ProffName", clients.ProffID);
ViewBag.Metapel = new SelectList(db.Workers, "ID", "WorkerName", clients.Metapel);
return View(clients);
}
My ProffController:
public ActionResult ProffVM_Read(string text)
{
var Proff_Tbl = db.ProfTBL.Select(proff => new ProffVm { ID = proff.ID, ProffName = proff.ProffName });
if (!string.IsNullOrEmpty(text))
{
Proff_Tbl = Proff_Tbl.Where(p => p.ProffName.Contains(text));
}
return Json(Proff_Tbl, JsonRequestBehavior.AllowGet);
}
and the Kendo combo:
#Html.Label("Proff")
#(Html.Kendo().ComboBoxFor(model => model.ProffID)
.Name("proffCbo")
.DataTextField("ProffName")
.DataValueField("ID")
.Events(e => e
.Select("proffCbo_select")
.Change("proffCbo_change")
)
.DataSource(source =>
{
source.Read(read =>
{
read.Action("ProffVM_Read", "Proff")
.Data("onAdditionalData");
});
})
)
where am i wrong ???
i can change this combo to textbox but... i have to realize the magic.
Thanks
Change these two lines
var Proff_Tbl = db.ProfTBL.Select(proff => new ProffVm { ID = proff.ID, ProffName = proff.ProffName });
Proff_Tbl = Proff_Tbl.Where(p => p.ProffName.Contains(text));
to
var Proff_Tbl = db.ProfTBL.Select(proff => new ProffVm { ID = proff.ID, ProffName = proff.ProffName }).ToList();
Proff_Tbl = Proff_Tbl.Where(p => p.ProffName.Contains(text)).ToList();
I have tried itextsharp samples and the serializing to xml .
Am using Entity frame work 6.0
and asp.net mvc4
I'm using following for export to excel:
In your Controller:
public ActionResult ExportData()
{
var datasource = db.Products.ToList();
GridView gv = new GridView();
gv.DataSource = datasource;
gv.DataBind();
Response.ClearContent();
Response.Buffer = true;
Response.AddHeader("content-disposition", "attachment; filename=Report.xls");
Response.ContentType = "application/ms-excel";
Response.Charset = "";
StringWriter sw = new StringWriter();
HtmlTextWriter htw = new HtmlTextWriter(sw);
gv.RenderControl(htw);
Response.Output.Write(sw.ToString());
Response.Flush();
Response.End();
return Json("Success");
}
In View:
#using (Html.BeginForm("ExportData", "Home", FormMethod.Post))
{
<button type="Submit">Export to Excel</button>
}
//OR:
#Html.ActionLink("Export to Excel", "ExportData", "Home")
As to export to PDF, I'd recommend to use Rotativa. Works ok for me.
EDITED
I'm using filters too. You may send it's value from View to controller action and modify datasource. For example:
public ActionResult ExportData(DateTime fromDate)
{
var datasource = db.Products.Where(g=>g.Date <= fromDate).ToList();
Try this:
var data = GetFeedbackDetailsExport();
var gridWeb = new WebGrid(source: data, canPage: false, canSort: false);
string exportData = gridWeb.GetHtml(
columns: gridWeb.Columns(
gridWeb.Column("EnterpriseId", "EnterpriseId"),
gridWeb.Column("GroupName", "Group Name"),
gridWeb.Column("Geography", "Geography"),
gridWeb.Column("Country", "Country"),
gridWeb.Column("DeliveryCentre", "Delivery Centre"),
gridWeb.Column("Vendor", "Vendor Name"),
gridWeb.Column("Category", "Category"),
gridWeb.Column("ModelName", "ModelName"),
gridWeb.Column("Status", "Status"),
gridWeb.Column("Date_Submitted", "Submitted On", format: (item) => item.Date_Submitted != null ? item.Date_Submitted.ToString("dd/MMM/yyyy") : ""),
gridWeb.Column("UpdatedBy", "Feedback Given By", style: "col-lg-1"),
gridWeb.Column("UpdatedOn", "Feedback Given On", format: (item) => item.UpdatedOn != null ? item.UpdatedOn.ToString("dd/MMM/yyyy") : "")
)
).ToHtmlString();
return File(new System.Text.UTF8Encoding().GetBytes(exportData),
"application/vnd.ms-excel",
"FeedbackReport.xls");
I am having a bit of a headache with a thing (I know something like has been asked before, but I'm pretty sure it's not quite the same thing).
To the point:
I have a View with a Telerik grid. On that grid I show some stuff from the model that I pass to the View BUT I want in the final column to put a CheckBox that is checked/unchecked based on some things in the Controller (the checks have nothing to do with the model that is being passed). In my ActionResult function that takes care of the View I store some Boolean values in the ViewData, and then I set the isChecked value in the CheckBox based on the values stored in the ViewData.
The code for the ActionResult is as follows:
[SecureThis(Roles = "User")]
public ActionResult Index()
{
//get bucket ids
var buckets = db.Buckets.ToList();
int i=1;
string cb = "checkbox" + i.ToString();
foreach (Bucket b in buckets)
{
var payByInvoice = db.PaymentOptions.Where(p => p.BucketId == b.Id).Select(p => p.CanPayByInvoice).SingleOrDefault();
if (payByInvoice == (int)PayByInvoiceState.Accepted)
ViewData["checkbox" + i.ToString()] = true;
else ViewData["checkbox" + i.ToString()] = false;
i++;
cb = "checkbox" + i.ToString();
}
return View(db.Buckets);
}
And the grid that should show all the stuff is this:
#{
int i=1;
string cb = "checkbox" + i.ToString();
}
#(Html.Telerik().Grid(Model)
.Name("BucketsGrid")
.DataKeys(keys => keys.Add(bucket => bucket.Id))
.Columns(
columns =>
{
columns.Template(model => ViewData[model.Id.ToString()])
.HeaderTemplate(
#<b>#Strings.Title_Customer</b>
);
columns.Bound(model => model.CreditFacility);
columns.Bound(model => model.Minimum);
columns.Bound(model => model.RefillLevel);
columns.Bound(model => model.NotificationEmail);
columns.Bound(model => model.NotificationSms);
columns.Template(model => Html.ActionLink(Strings.Edit, "Edit", new { id = model.Id }));
columns.Template(model => Html.ActionLink(Strings.NotificationOptions, "Bucket", "NotificationOptions", new { id = model.Id }, null));
columns.Template(model => Html.ActionLink("Refill", "Refill", "Payment", new { id = model.Id }, null));
columns.Template(model => Html.ActionLink(Strings.Details, "Details", new { id = model.Id }));
columns.Template(model => Html.ActionLink(Strings.Delete, "Delete", new { id = model.Id }));
columns.Template(model => Html.CheckBox("invoice", (Boolean)ViewData[#cb])).HeaderTemplate("Invoice Option");
#i++;
#cb = "checkbox" + i.ToString();
}
)
.Pageable(paging =>
paging.Enabled(true)
.PageSize(UserSettings.GridPageSize)
.Style(GridPagerStyles.NextPrevious)
.Position(GridPagerPosition.Bottom)
)
.Sortable()
.Scrollable()
.Resizable(resize=> resize.Columns(true))
)
The problem with this whole thing is that the checkboxes remain unchecked, no matter the data stored in the ViewData. I went with the debugger and the values are se accordingly in the ViewData, but for some reason (that I cannot yet tell) the checkboxes still remain unchcked.
Any ideas on this matter would be much appreciated.
I have found out the problem of all this. As expected, it was my own doing (or so to say). The problem was that I incremented the #i variable inside the Telerik grid declaration, thinking that it would happen for all the rows in the grid, but that thing is only triggered once. Hence, the ViewData[#cb] value would always have the 2nd value set in the Controller (which in my case was false) and all the checkboxes would then be unchecked.
The fix:
I used the ViewBag and set it up with a Dictionary<Guid, bool> to hold my values, and iterate through it using the model.Id property. For anyone who might be interested I'll post the code below.
Controller:
ViewBag.Dict = new Dictionary<Guid, bool>();
Dictionary<Guid, bool> dict = new Dictionary<Guid, bool>();
foreach (Bucket b in buckets)
{
var payByInvoice = db.PaymentOptions.Where(p => p.BucketId == b.Id).Select(p => p.CanPayByInvoice).SingleOrDefault();
if (payByInvoice != (int)PayByInvoiceState.Accepted)
{
dict.Add(b.Id, false);
}
if (payByInvoice == (int)PayByInvoiceState.Accepted)
{
dict.Add(b.Id, true);
}
}
ViewBag.Dict = dict;
View:
columns.Template(model => Html.CheckBox("invoice", (bool)ViewBag.Dict[model.Id])).HeaderTemplate("Invoice option");