Friday, December 22, 2017

Multiple PagedList Pager In A Single View

Good afternoon!
In a situation wherein a single page will contain multiple paging such as displaying master-details records or similar requirements, using a couple or more PagedList pager will cause logical errors such as when you click on the paging of details record to traverse to the next page, the paging of master record will move to the next record as well. In order to solve this dilemma, we need to assign a specific page variable to a PagedList object to prevent this issue from happening. In this example, I'll demonstrate showing products information from AdventureWorks database whose stocks are above or below a certain reorder point. The page model class below has two page properties namely BelowReorderPage and AboveReorderPage. And these properties are assigned to their specific PagedList object whether ProductsBelowReorder or ProductsAboveReorder.
PageModel.cs
public class PageModel
{
 public int BelowReorderPage { get; set; }
 public int AboveReorderPage { get; set; }
 public int Size { get; set; }

 public PageModel()
 {
  BelowReorderPage = 1;
  AboveReorderPage = 1;
  Size = 10;
 }
}

public class ProductPageModel
{
 public PageModel PageModel { get; set; }
 public ProductPageModel(PageModel pageModel)
 {
  ProductsBelowReorder = new PagedList<ProductViewModel>(new List<ProductViewModel>(), 1, pageModel.Size);
  ProductsAboveReorder = new PagedList<ProductViewModel>(new List<ProductViewModel>(), 1, pageModel.Size);
  PageModel = pageModel;
 }

 public IPagedList<ProductViewModel> ProductsBelowReorder { get; set; }
 public IPagedList<ProductViewModel> ProductsAboveReorder { get; set; }
}
The controller class will retrieve the records from the Product table and assign them to the PagedList properties. Note that the ProductsBelowReorder PagedList property is assigned with the BelowReorderPage page while the ProductsAboveReorder is allocated with AboveReorderPage page.
HomeController.cs
public class HomeController : Controller
{
 private AdventureWorksEntities _context;

 public HomeController()
 {
  _context = new AdventureWorksEntities();
 }
 
 // GET: Home
 public ActionResult Index(PageModel pageModel)
 {
  var productsBelowReorder = (from prod in _context.Products
         join prodInv in _context.ProductInventories
         on prod.ProductID equals prodInv.ProductID
         where prodInv.Quantity < prod.ReorderPoint
         select new ProductViewModel()
         {
          ProductID = prod.ProductID,
          ProductName = prod.Name,
          ProductNumber = prod.ProductNumber,
          ListPrice = prod.ListPrice,
          LocationID = prodInv.LocationID,
          Quantity = prodInv.Quantity,
          ReorderPoint = prod.ReorderPoint
         }).ToList();

  var productsAboveReorder = (from prod in _context.Products
         join prodInv in _context.ProductInventories
         on prod.ProductID equals prodInv.ProductID
         where prodInv.Quantity >= prod.ReorderPoint
         select new ProductViewModel()
         {
          ProductID = prod.ProductID,
          ProductName = prod.Name,
          ProductNumber = prod.ProductNumber,
          ListPrice = prod.ListPrice,
          LocationID = prodInv.LocationID,
          Quantity = prodInv.Quantity,
          ReorderPoint = prod.ReorderPoint
         }).ToList();

  var model = new ProductPageModel(pageModel)
  {
   ProductsBelowReorder = productsBelowReorder.ToPagedList(pageModel.BelowReorderPage, pageModel.Size),
   ProductsAboveReorder = productsAboveReorder.ToPagedList(pageModel.AboveReorderPage, pageModel.Size)
  };

  return View(model);
 }
}
The view will display each product information in a tabular format and is assigned with a PagedListPager helper. Each pager has been assigned with a particular model and paging options. For the products whose stocks are above the reorder point, the RouteValueDictionary parameter sets the AboveReorderPage with the current page while the BelowReorderPage is assigned with the BelowReorderPage page. The approach also applies to the products whose stocks are below the reorder point.
Index.cshtml
<div class="container">
    <div class="row table-responsive">
        <h3>Products Above ReorderPoint</h3>
        <table class="table table-bordered table-condensed table-striped">
            <thead>
                <tr>
                    <th>Product ID</th>
                    <th>Product Name</th>
                    <th>Product Number</th>
                    <th>ListPrice</th>
                    <th>Location ID</th>
                    <th>Quantity</th>
                    <th>Reorder Point</th>
                </tr>
            </thead>
            <tbody>
                @foreach (var productAboveReorder in Model.ProductsAboveReorder)
                {
                    <tr>
                        <td>@productAboveReorder.ProductID</td>
                        <td>@productAboveReorder.ProductName</td>
                        <td>@productAboveReorder.ProductNumber</td>
                        <td>@productAboveReorder.ListPrice</td>
                        <td>@productAboveReorder.LocationID</td>
                        <td>@productAboveReorder.Quantity</td>
                        <td>@productAboveReorder.ReorderPoint</td>
                    </tr>
                }
            </tbody>
        </table>
        @Html.PagedListPager(Model.ProductsAboveReorder, page => Url.Action("Index",
                                    "Home",
                                      new RouteValueDictionary() {
                                        { "AboveReorderPage", page },
                                        { "BelowReorderPage", Model.PageModel.BelowReorderPage }
                                      }), PagedListRenderOptions.ClassicPlusFirstAndLast)
    </div>
    <div class="row table-responsive">
        <h3>Products Below ReorderPoint</h3>
        <table class="table table-bordered table-condensed table-striped">
            <thead>
                <tr>
                    <th>Product ID</th>
                    <th>Product Name</th>
                    <th>Product Number</th>
                    <th>ListPrice</th>
                    <th>Location ID</th>
                    <th>Quantity</th>
                    <th>Reorder Point</th>
                </tr>
            </thead>
            <tbody>
                @foreach (var productBelowReorder in Model.ProductsBelowReorder)
                {
                    <tr>
                        <td>@productBelowReorder.ProductID</td>
                        <td>@productBelowReorder.ProductName</td>
                        <td>@productBelowReorder.ProductNumber</td>
                        <td>@productBelowReorder.ListPrice</td>
                        <td>@productBelowReorder.LocationID</td>
                        <td>@productBelowReorder.Quantity</td>
                        <td>@productBelowReorder.ReorderPoint</td>
                    </tr>
                }
            </tbody>
        </table>
        @Html.PagedListPager(Model.ProductsBelowReorder, page => Url.Action("Index",
                                    "Home",
                                      new RouteValueDictionary() {
                                        { "BelowReorderPage", page },
                                        { "AboveReorderPage", Model.PageModel.AboveReorderPage }
                                      }), PagedListRenderOptions.ClassicPlusFirstAndLast)
    </div>
</div>
Output Source Code: Github - Multiple PagedList Pager

Wednesday, December 20, 2017

DataList in ASP.NET MVC with Paging Using PagedList and Bootstrap

Here's an example ASP.NET MVC application that shows information in a DataList layout with pagination using PagedList Pager. The project also integrates Bootstrap for enhancing the UI and display the images from AdventureWorks Products table through an ImageHandler class. The significant files used in this project are:
1. PagingModel.cs/IndexModel.cs - These classes are responsible for defining the page number, size of page, and PagedList property that stores the information that are paged accordingly to it's size.
public class PagingModel
{
 public PagingModel()
 {
  Size = 24;
  Page = 1;
 }

 public int Page { get; set; }
 public int Size { get; set; }
}

public class IndexModel
{
 public PagingModel PageModel { get; set; }

 public IndexModel(PagingModel pageModel)
 {
  Products = new PagedList<ProductViewModel>(new List<ProductViewModel>(), 1, pageModel.Size);
  PageModel = pageModel;
 }

 public IPagedList<ProductViewModel> Products { get; set; }
}
2. ProductRepository.cs - this class is responsible for retrieving the products from the table and it's thumbnail photo.
public class ProductRepository
{
 AdventureWorks2012Entities context;

 public ProductRepository()
 {
  context = new AdventureWorks2012Entities();
 }

 public IEnumerable<ProductViewModel> GetProducts()
 {
  List<ProductViewModel> products = new List<ProductViewModel>();

  products = (from prod in context.Products
       join productProductPhoto in context.ProductProductPhotoes on prod.ProductID equals productProductPhoto.ProductID
       join productPhoto in context.ProductPhotoes on productProductPhoto.ProductPhotoID equals productPhoto.ProductPhotoID
       where prod.ListPrice > 0
       select new ProductViewModel()
       {
      ProductID = prod.ProductID,
      ProductName = prod.Name,
      ProductNumber = prod.ProductNumber,
      ListPrice = prod.ListPrice,
      Image = productPhoto.LargePhoto
       }).ToList();            
  return products;
 }

 public ProductViewModel Product(int productId)
 {
  ProductViewModel product = new ProductViewModel();
  product = (from prod in context.Products
       join productProductPhoto in context.ProductProductPhotoes on prod.ProductID equals productProductPhoto.ProductID
       join productPhoto in context.ProductPhotoes on productProductPhoto.ProductPhotoID equals productPhoto.ProductPhotoID
       where productId == prod.ProductID
       select new ProductViewModel()
       {
        Image = productPhoto.ThumbNailPhoto
       }).FirstOrDefault();

  return product;
 }
}
3. Index.cshtml - This is the page that will display the products information in a tabular format and has a PagedListPager helper that navigates the record through page numbers and other paging options.
@model DataListInASPMVCWithPaging.Models.IndexModel
@using PagedList
@using PagedList.Mvc

<h2>Product Listing</h2>

<div class="row">
    <div class="col-md-12">
        @Html.PagedListPager(Model.Products, page => Url.Action("Index",
                            "Product",
                                new RouteValueDictionary() {
                                { "Page", page }
                                }), PagedListRenderOptions.ClassicPlusFirstAndLast)
    </div>
</div>
<div class="row">
    @if (Model.Products.Count > 0)
    {
        foreach (var item in Model.Products)
        {
            <div class="col-md-2 col-sm-6 col-xs-12" style="text-align:left;">
                <div style="background-color:moccasin; padding:10px; border-radius:15px; margin-bottom:20px;">
                    <img src="~/Helpers/ImageHandler.ashx?ProductID=@item.ProductID" style="width:50%;" />
                    <h3>@item.ProductNumber</h3>
                    <p>@item.ProductName</p>
                    <p>@string.Format("{0:0,0.00}", Convert.ToDouble(item.ListPrice))</p>
                    <div>
                        @Html.ActionLink("Add To Cart", "", "", null, new { @class = "actionButton btn btn-xs btn-primary" })
                    </div>
                </div>
            </div>
        }
    }

</div>
Output Source Code
DataList In ASP.NET MVC With Paging (Github)

Saturday, December 16, 2017

ASP.NET GridView With Running Total Per Group using JavaScript

Basing from the post DataTable With Running Total Per Group which applies running total to a DataTable object, we can also achieve the same functionality through the front-end side by changing the structure of the GridView control given that this is an ASP.NET WebForm application. The snippet to set the control's data source is simple such as below:
 dt.Columns.AddRange(new DataColumn[5]
     { new DataColumn("SrNo", typeof(int)),
    new DataColumn("PartyName", typeof(string)),
    new DataColumn("ItemName",typeof(string)),
    new DataColumn("ChqAmt", typeof(int)),
    new DataColumn("PartyCode",typeof(string))});
 dt.Rows.Add(1, "ABC Water Supply", "Construction Service", 400, "ABC");
 dt.Rows.Add(2, "ABC Pump Services", "Type 24 Engine Pump", 150, "ABC");
 dt.Rows.Add(3, "ABC Water Supply", "12 Ft Water Tank", 600, "ABC");
 dt.Rows.Add(4, "XYZ Hardware", "Garden Soil", 250, "XYZ");
 dt.Rows.Add(5, "XYZ Hardware", "Power Generator", 245, "XYZ");
 dt.Rows.Add(6, "ACE Hardware", "Screw Driver", 16, "ACE");
 dt.Rows.Add(7, "ACE Hardware", "8W Led Bulb", 18, "ACE");
 GridView1.DataSource = dt;
 GridView1.DataBind();
}
The GridView control has BoundField columns used to display the information.
<div id="content">
 <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" BackColor="White" BorderColor="#3366CC" BorderStyle="None" BorderWidth="1px" CellPadding="4">
  <Columns>
   <asp:BoundField DataField="SrNo" HeaderText="SrNo" />
   <asp:BoundField DataField="PartyName" HeaderText="PartyName" />
   <asp:BoundField DataField="ItemName" HeaderText="ItemName" />
   <asp:BoundField DataField="ChqAmt" HeaderText="ChqAmt" >
    <ItemStyle HorizontalAlign="Right" />
   </asp:BoundField>
   <asp:BoundField DataField="PartyCode" HeaderText="PartyCode" ItemStyle-CssClass="hiddencol" HeaderStyle-CssClass="hiddencol"/>
  </Columns>
  <FooterStyle BackColor="#99CCCC" ForeColor="#003399" />
  <HeaderStyle BackColor="#003399" Font-Bold="True" ForeColor="#CCCCFF" />
  <PagerStyle BackColor="#99CCCC" ForeColor="#003399" HorizontalAlign="Left" />
  <RowStyle BackColor="White" ForeColor="#003399" />
  <SelectedRowStyle BackColor="#009999" Font-Bold="True" ForeColor="#CCFF99" />
  <SortedAscendingCellStyle BackColor="#EDF6F6" />
  <SortedAscendingHeaderStyle BackColor="#0D4AC4" />
  <SortedDescendingCellStyle BackColor="#D6DFDF" />
  <SortedDescendingHeaderStyle BackColor="#002876" />
 </asp:GridView>
</div>
The JavaScript code will loop through the table and does the calculation plus adding another table row to display the running total.
$(document).ready(function () {
 var table = $('table');
 var subtotal = 0;
 var grandTotal = 0;
 var flag = $('table tr:eq(1) td:eq(4)').text(); //assign code to flag from second table row after th.
 var tblLength = $('table tr').length;
 for (var index = 0; index < tblLength; index++) {
  if ($('table tr:eq(' + index + ')').find('td:eq(4)').text() != "") {
   var temp = $('table tr:eq(' + index + ')').find('td:eq(4)').text();
   if (temp != flag) {
    var html = "<tr style='color:#003399;background-color:White;'>"
        + "<td></td>"
        + "<td>" + "Total For " + $('table tr:eq(' + parseInt(index - 1) + ')').find('td:eq(4)').text() + "</td>"
        + "<td></td>"
        + "<td align='right'>" + subtotal + "</td>"
        + "<td class='hiddencol'></td>"
        + "</tr>";
    $('table tbody tr:eq(' + parseInt(index - 1) + ')').after(html);
    tblLength = $('table tr').length;
    grandTotal = parseFloat(grandTotal) + parseFloat(subtotal);
    subtotal = 0;
    flag = $('table tbody tr:eq(' + parseInt(index + 1) + ')').find('td:eq(4)').text();
    continue;
   }
   else {
    subtotal = parseInt(subtotal) + parseInt($('table tr:eq(' + index + ')').find('td:eq(3)').text());
    var len = $('table tr').length - 1;
    if (index == len) {
     var html = "<tr  style='color:#003399;background-color:White;'>"
          + "<td></td>"
          + "<td>" + "Total For " + $('table tr:eq(' + index + ')').find('td:eq(1)').text() + "</td>"
          + "<td></td>"
          + "<td align='right'>" + subtotal + "</td>"
          + "<td class='hiddencol'></td>"
          + "</tr>";
     $('table tbody tr:eq(' + parseInt(index) + ')').after(html);
     grandTotal = parseFloat(grandTotal) + parseFloat(subtotal);

     //insert grand total
     var htmlGrandTotal = "<tr  style='color:#003399;background-color:White;'>"
         + "<td></td>"
         + "<td>" + "Grand Total </td>"
         + "<td></td>"
         + "<td align='right'>" + grandTotal + "</td>"
         + "<td class='hiddencol'></td>"
         + "</tr>";
     $('table tbody tr:eq(' + parseInt(index + 1) + ')').after(htmlGrandTotal);
    }
   }
  }
 }

 $('table tr').each(function () {
  $(this).find('td').eq(3).text(parseFloat($(this).find('td').eq(3).text()).toLocaleFixed(2));
 });
});

Number.prototype.toLocaleFixed = function (n) {
 return this.toLocaleString(undefined, {
  minimumFractionDigits: n,
  maximumFractionDigits: n
 });
};
Screenshot

Friday, December 15, 2017

DataTable With Running Total Per Group

Good Evening!
There was a question raised by a developer if it's possible to compute the running total of a specific DataTable column per grouping or category. The solution is to mark the category as a flag variable that indicates the group to be calculated. The sample code below creates a DataTable object with fictitious information of hardware materials that belong to a particular group specifically PartyCode column. If a column belongs to that group, it will perform calculations. If not, reset the flag variable and total so as to perform new calculations. When computing totals for large number of records, make sure to sort the DataTable using it's category.
DataTable dt = new DataTable();
dt.Columns.AddRange(new DataColumn[5] 
    { new DataColumn("SrNo", typeof(int)),
   new DataColumn("PartyName", typeof(string)),
   new DataColumn("ItemName",typeof(string)),
   new DataColumn("ChqAmt", typeof(int)),
   new DataColumn("PartyCode",typeof(string))});
dt.Rows.Add(1, "ABC Water Supply", "Construction Service", 400,"ABC");
dt.Rows.Add(2, "ABC Pump Services", "Type 24 Engine Pump", 150, "ABC");
dt.Rows.Add(3, "ABC Water Supply", "12 Ft Water Tank", 600, "ABC");
dt.Rows.Add(4, "XYZ Hardware", "Garden Soil", 250, "XYZ");
dt.Rows.Add(5, "XYZ Hardware", "Power Generator", 245, "XYZ");
dt.Rows.Add(6, "ACE Hardware", "Screw Driver", 16, "ACE");
dt.Rows.Add(7, "ACE Hardware", "8W Led Bulb", 18, "ACE");

string flag = dt.Rows[0][4].ToString();
int subTotal = 0;
int grandTotal = 0;
for (int i = 0; i < dt.Rows.Count; i++)
{
 if (dt.Rows[i][4].ToString() != flag)
 {
  DataRow toInsert = dt.NewRow();
  toInsert[0] = DBNull.Value;
  toInsert[1] = string.Format("Total For {0}", dt.Rows[i-1][1].ToString());
  toInsert[2] = "";
  toInsert[3] = subTotal;
  toInsert[4] = null;
  dt.Rows.InsertAt(toInsert, i);
  grandTotal += subTotal;
  subTotal = 0;
  flag = dt.Rows[i+1][4].ToString();
  continue;
 }
 else
 {
  subTotal += Convert.ToInt32(dt.Rows[i][3].ToString());
  if (i == dt.Rows.Count - 1)
  {
   DataRow toInsert = dt.NewRow();
   toInsert[0] = DBNull.Value;
   toInsert[1] = string.Format("Total For {0}", dt.Rows[i][1].ToString());
   toInsert[2] = "";
   toInsert[3] = subTotal;
   toInsert[4] = null;
   dt.Rows.InsertAt(toInsert, i+1);
   grandTotal += subTotal;

   //insert grand total
   int totalIndex = i + 1;
   DataRow grandTotalInsert = dt.NewRow();
   grandTotalInsert[0] = DBNull.Value;
   grandTotalInsert[1] = "Grand Total";
   grandTotalInsert[2] = "";
   grandTotalInsert[3] = string.Format("{0}", grandTotal);
   grandTotalInsert[4] = null;
   dt.Rows.InsertAt(grandTotalInsert, totalIndex + 1);
   break;
  }
 }
}

GridView1.DataSource = dt;
GridView1.DataBind();
Output

Sunday, December 3, 2017

HTTP Error 500.23 - Internal Server Error. An ASP.NET setting has been detected that does not apply in Integrated managed pipeline mode. (ASP.NET MVC HttpHandler)

Good day!
I was trying to apply integrate an Image HttpHandler that discourages leeching from one of my Web Forms project to ASP.NET MVC. This hack is found on ASP.NET 2.0 MVP Hacks site. Upon running the ASP.NET MVC project, an issue was thrown to the browser specifically "HTTP Error 500.23 - Internal Server Error. An ASP.NET setting has been detected that does not apply in Integrated managed pipeline mode." Upon investigating, I found out that handlers in WebForms are declared in <httpHandlers> under <system.web>.
<system.web>
 <httpHandlers>
  <add verb="*" path="*.jpg" type="Events.Web.Extensions.NoLeechImageHandler"/>
  <add verb="*" path="*.jpeg" type="Events.Web.Extensions.NoLeechImageHandler"/>
  <add verb="*" path="*.gif" type="Events.Web.Extensions.NoLeechImageHandler"/>
  <add verb="*" path="*.png" type="Events.Web.Extensions.NoLeechImageHandler"/>
 </httpHandlers>
</system.web> 
And handlers in MVC are set inside the <handlers> node belonging to <system.webServer>.
<system.webServer>
 <handlers>
   <add name="jpgHandler" verb="*" path="*.jpg" type="Events.Web.Extensions.NoLeechImageHandler"/>
   <add name="jpegHandler" verb="*" path="*.jpeg" type="Events.Web.Extensions.NoLeechImageHandler"/>
   <add name="gifHandler" verb="*" path="*.gif" type="Events.Web.Extensions.NoLeechImageHandler"/>
   <add name="pngHandler" verb="*" path="*.png" type="Events.Web.Extensions.NoLeechImageHandler"/>
 </handlers>
</system.webServer>
That fixed the issue for ASP.NET MVC.

Friday, December 1, 2017

Hide GridView BoundField column with value accessible through JavaScript

To hide a BoundField column but make it's value still accessible through JavaScript just set column's ItemStyle-CssClass and HeaderStyle-CssClass properties using CSS class with value display:none.
CSS
.hiddenColumn{
 display:none;
}
ASPX
<asp:BoundField DataField="GroupCode" HeaderText="Group Code" ItemStyle-CssClass="hiddenColumn" HeaderStyle-CssClass="hiddenColumn"/>

Monday, November 20, 2017

Display Images Using Generic Handler in ASP.NET MVC

There are several options on how to show images in ASP.NET MVC. One of them is using a generic handler. This method was applied since the early days of ASP.NET Webforms and still can be used with recent frameworks. The class below will render the images on the page by calling the ProcessRequest method which will then get the image from datasources such as database and file system and return it as a Bitmap object.
public class ImageHandler : IHttpHandler
{
 private OnlineShoppingDBEntities shoppingContext;

 public ImageHandler()
 {
  shoppingContext = new OnlineShoppingDBEntities();
 }

 public void ProcessRequest(HttpContext context)
 {
  if (context.Request.QueryString["ProductID"] != null)
  {
   Product product = shoppingContext.Products.Find(Convert.ToInt32(context.Request.QueryString["ProductID"]));
   if (product != null)
   {
    Byte[] bytes = product.Image;
    int height = 0;
    int width = 0;

    height = 100;
    width = 100;

    Bitmap image = GetImage(bytes, height, width);

    context.Response.Buffer = true;
    context.Response.Charset = "";
    context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
    context.Response.ContentType = "image/jpeg";
    image.Save(context.Response.OutputStream, ImageFormat.Jpeg);
    context.Response.Flush();
    context.Response.End();
   }
  }
 }

 private Bitmap GetImage(Byte[] bytes, int width, int height)
 {
  Image originalImage;
  using (MemoryStream ms = new MemoryStream(bytes))
  {
   originalImage = Image.FromStream(ms);
  }

  var newImage = new Bitmap(originalImage, width, height);
  Graphics g = Graphics.FromImage(originalImage);
  g.FillRectangle(Brushes.White, 0, 0, newImage.Width, newImage.Height);
  Rectangle Box = new Rectangle(10, 10, newImage.Size.Width - 20, newImage.Size.Height - 20);
  g.DrawRectangle(Pens.Black, Box);
  return newImage;
 }

 public bool IsReusable
 {
  get
  {
   return false;
  }
 }
}
When using this code to show images of type GIF, you might encounter an issue such as "A Graphics object cannot be created from an image that has an indexed pixel format". The fix for that is to revise the GetImage() method wherein you create a blank bitmap with the same dimensions and the correct PixelFormat and then draw on that bitmap the original image bitmap.
public class ImageHandler : IHttpHandler
{

 ProductRepository repository;

 public ImageHandler()
 {
  repository = new ProductRepository();
 }

 public void ProcessRequest(HttpContext context)
 {
  if (context.Request.QueryString["ProductID"] != null)
  {
   ProductViewModel product = repository.Product(Convert.ToInt32(context.Request.QueryString["ProductID"]));
   if (product != null)
   {
    Byte[] bytes = product.Image;
    Bitmap image = GetImage(bytes);

    context.Response.Buffer = true;
    context.Response.Charset = "";
    context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
    context.Response.ContentType = "image/jpeg";
    image.Save(context.Response.OutputStream, ImageFormat.Jpeg);
    context.Response.Flush();
    context.Response.End();
   }
  }
 }

 private Bitmap GetImage(Byte[] bytes)
 {
  Image originalImage;
  Bitmap originalBmp;
  using (MemoryStream ms = new MemoryStream(bytes))
  {
   originalImage = Image.FromStream(ms);
  }

  originalBmp = new Bitmap(originalImage);
  Bitmap tempBitmap = new Bitmap(originalBmp.Width, originalBmp.Height);
  using (Graphics g = Graphics.FromImage(tempBitmap))
  {
   // Draw the original bitmap onto the graphics of the new bitmap
   g.DrawImage(originalBmp, 0, 0);
   Rectangle Box = new Rectangle(0, 0, tempBitmap.Size.Width, tempBitmap.Size.Height);
   g.DrawRectangle(Pens.White, Box);
  }

  return tempBitmap;
 }

 public bool IsReusable
 {
  get
  {
   return false;
  }
 }
}
Another modification to the class below will solve the issue on displaying images with OLE header which will check if the image format is of type RawFormat.
public class ImageHandler : IHttpHandler
{
 private NorthwindEntities _context;

 public ImageHandler()
 {
  _context = new NorthwindEntities();
 }
 
 public void ProcessRequest(HttpContext context)
 {
  if (context.Request.QueryString["EmployeeID"] != null)
  {
   var employee = _context.Employees.Find(Convert.ToInt32(context.Request.QueryString["EmployeeID"]));
   if (employee != null)
   {
    Byte[] bytes = employee.Photo;
    Bitmap image = GetImage(bytes);

    context.Response.Buffer = true;
    context.Response.Charset = "";
    context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
    context.Response.ContentType = "image/jpeg";
    image.Save(context.Response.OutputStream, ImageFormat.Jpeg);
    context.Response.Flush();
    context.Response.End();
   }
  }
 }

 private Bitmap GetImage(Byte[] bytes)
 {
  Image originalImage;
  Bitmap originalBmp;

  using (MemoryStream ms = new MemoryStream(bytes))
  {
   Image xImage = (Bitmap)((new ImageConverter()).ConvertFrom(bytes));
   if (ImageFormat.Bmp.Equals(xImage.RawFormat))
   {
    ms.Write(bytes, 78, bytes.Length - 78);
   }
   else
   {
    ms.Write(bytes, 0, bytes.Length);
   }

   originalImage = Image.FromStream(ms);
  }

  originalBmp = new Bitmap(originalImage);
  Bitmap tempBitmap = new Bitmap(originalBmp.Width, originalBmp.Height);
  using (Graphics g = Graphics.FromImage(tempBitmap))
  {
   // Draw the original bitmap onto the graphics of the new bitmap
   g.DrawImage(originalBmp, 0, 0);
   Rectangle Box = new Rectangle(0, 0, tempBitmap.Size.Width, tempBitmap.Size.Height);
   g.DrawRectangle(Pens.White, Box);
  }

  return tempBitmap;
 }

 public bool IsReusable
 {
  get
  {
   return false;
  }
 }
}
To use this class, all you need to do is add an img tag in your view and replace the src attribute with the relative path of the handler and append the model id as query string.
<img src="~/Helpers/ImageHandler.ashx?ProductID=@item.ProductID" />
Rendered View:

Sunday, November 19, 2017

Add glyphicon to Ajax.ActionLink() in ASP.NET MVC

Good evening!
Adding a Bootstrap glyphicon to Ajax.ActionLink() helper is similar with Html.ActionLink() except that when the linkText parameter of the helper is empty, it will cause an Ajax issue and an Internal Server Error will be thrown from the browser. If you're going to integrate glyphicons on Ajax.ActionLink() helper and exclude the linkText property, supply that parameter with space instead of empty string so as not to cause jQuery or Ajax issues.
@Ajax.ActionLink(" ", "DeleteComment", "Home",
    new { id = comment.CommentID },
    new AjaxOptions
    {
     OnBegin = "return confirm('Are you sure you want to delete this comment?');",
     InsertionMode = InsertionMode.Replace,
     UpdateTargetId = "event-details-" + Model.Id,
     HttpMethod = "GET",                                  
    }, new 
    {  
     @class = "commentDelete glyphicon glyphicon-trash"
    });
linkText is the first parameter of Ajax.ActionLink() helper.
Output:

Thursday, November 9, 2017

Invalid nested tag div found, expected closing tag input

Hello all,
I've been experimenting on how to print html document using the said 3rd party software called iTextSharp. iTextSharp is a popular tool and has several examples on the internet regarding integration to the project and occurring issues. One of the issue I encountered is Invalid nested div tag and is expecting a closing tag input. As I trace back my html source, the tags are well-formed except that they are self closing tags such as <input>, <hr>, <img>, <br> or the like. These tags when passed to an action method as string are not properly closed and thus an issue is thrown by iTextSharp's XMLWorkerHelper's ParseXHtml() method.
<img src="~/Images/success.png" /> 
<input type="hidden" name="OrderStatusHTML" />
<input type="submit" id="btnSubmit" value="Export to PDF" class="btn btn-success" />
The solution I came up with is to fix the page source using HTMLAgilityPack which is to explicitly close the tags by assigning HtmlElementFlag.Closed enum to HtmlNode.ElementsFlag["img"] dictionary.
[HttpPost]
[ValidateInput(false)]
public FileResult ExportToPDF(string OrderStatusHTML)
{
 HtmlNode.ElementsFlags["img"] = HtmlElementFlag.Closed;
 HtmlNode.ElementsFlags["input"] = HtmlElementFlag.Closed;
 HtmlDocument doc = new HtmlDocument();
 doc.OptionFixNestedTags = true;
 doc.LoadHtml(OrderStatusHTML);
 OrderStatusHTML = doc.DocumentNode.OuterHtml;

 using (MemoryStream stream = new System.IO.MemoryStream())
 {
  Encoding unicode = Encoding.UTF8;
  StringReader sr = new StringReader(OrderStatusHTML);
  Document pdfDoc = new Document(PageSize.A4, 10f, 10f, 100f, 0f);
  PdfWriter writer = PdfWriter.GetInstance(pdfDoc, stream);
  pdfDoc.Open();
  XMLWorkerHelper.GetInstance().ParseXHtml(writer, pdfDoc, sr);
  pdfDoc.Close();
  return File(stream.ToArray(), "application/pdf", "OrderStatus.pdf");
 }
}

That's it.. :-D

Tuesday, November 7, 2017

Add glyphicon to Html.ActionLink() in ASP.NET MVC

Hello,
Here's how to integrate glyphicon to Html.ActionLink() helper in ASP.NET MVC. The code below will display the glyphicon shopping cart right after the text Checkout of the anchor element.
@Html.ActionLink("Checkout", "Index", "Home", null, new { @class = "btn btn-info glyphicon glyphicon-shopping-cart" })
In order to add the glyphicon before the text of the anchor element, use @Url.Action() instead.
<a href="@Url.Action("Index", "Checkout")" class="btn btn-info">
 <span class="glyphicon glyphicon-shopping-cart" ></span>Checkout
</a>
Output:

Thursday, November 2, 2017

Formatting numbers using toLocaleString() in JavaScript

I've been using a JavaScript 3rd party library to format numbers with comma and decimal place(s). The JavaScript library called NumberFormatter was introduced to me by my developer with exceptional skills in front-end programming. Due to simplicity sake, I'm exploring options if this can be achieved using an existing JavaScript function instead of using the existing 3rd party app.

After doing some research, I found an answer here: How to use toLocaleString() and tofixed(2) in javascript which is to use toLocaleString() by setting the options minimumFractionDigits and maximumFractionDigits to 2.
Number.prototype.toLocaleFixed = function (n) {
    return this.toLocaleString(undefined, {
        minimumFractionDigits: n,
        maximumFractionDigits: n
    });
};
Sample usage:
var result = parseFloat(amount).toLocaleFixed(2)

Saturday, October 21, 2017

Task Management System with Entity Framework and ASP.NET MVC

Hello,
Here's a simple Task Management System with Entity Framework 6 taken from Udemy's Asp.Net MVC With Entity Framework From Scratch video tutorial. The output of the project should be in ASP.NET Webform but I chose to upload a sample in ASP.NET MVC which is intended for ASP.NET MVC developers. The entire source code can be downloaded here:Task Management System MVC. The project includes the stored procedure necessary to display the data through the grid. As for the database table, it is included in the tutorial series through a PDF file.
Cheers!

Monday, October 16, 2017

Ajax.ActionLink() not redirecting to ActionResult with Ajax Attribute

Given that I have this code in my .cshtml page using Ajax.ActionLink() that calls a controller method using Ajax request:
@Ajax.ActionLink("Select", "TaskListing", new { id = item.TaskID }, 
   new AjaxOptions(){ 
    HttpMethod = "GET",
    UpdateTargetId = "taskListing",
    InsertionMode = InsertionMode.Replace
})
And the controller method called by the Ajax ActionLink is decorated with Ajax attribute.
[HttpGet]
[AjaxOnly(true)]
[ActionName("TaskListing")]
public ActionResult TaskListing_Ajax(int id = -1)
{
 var projects = projRep.GetAllProjects();
 var model = new TaskAndTaskViewModel();
 model.Task = te.Tasks.FirstOrDefault(t => t.TaskID == id);
 model.SelectList = from p in projRep.GetAllProjects()
        select new SelectListItem
        {
         Selected = (p.ProjectID == Convert.ToInt32(model.Task.ProjectID)),
         Text = p.ProjectName.ToString(),
         Value = p.ProjectID.ToString()
        };

 return PartialView("TaskForm", model);
}
Normally, the request would push through. If does not proceed, maybe you have not added the Microsoft JQuery Unobtrusive Ajax to your project. Downloading and installing the said package(Microsoft JQuery Unobtrusive Ajax) via NuGet might fix the problem.

Sunday, October 8, 2017

Read .NET configuration files using NameValueSectionHandler and AppSettingsSection Types

Hello all,
I've read from a tutorial NameValueCollection and .NET Configuration Files which targets .NET 1.0/1.1 on how to read config files using type NameValueSectionHandler. I intend to explore more on applying this concept to recent versions of .NET frameworks. Upon doing some diggings, I came up with two options. First is using NameValueSectionHandler type and the other one is AppSettingsSections. To begin with, I have this App.config file with XML elements scriptsfiles and docfiles all registered in configSections.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="scriptfiles" type="System.Configuration.NameValueSectionHandler"/>
    <section name="docfiles" type="System.Configuration.AppSettingsSection"/>
  </configSections>
  <scriptfiles>
    <add key="C:\batchfiles\2017" value="*.bat" />
    <add key="C:\vbs\2017" value="*.vbs" />
  </scriptfiles>
  <docfiles>
    <add key="C:\applicants\2017" value="*.doc" />
    <add key="C:\officemanuals\2017" value="*.pdf" />
  </docfiles>
  <startup> 
      <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
  </startup> 
</configuration>
If you noticed, each sections are declared with different types specifically NameValueSectionHandler and AppSettingsSection with similar node structures. To read the element with type NameValueSectionHandler we use the ConfigurationManager.GetSection() method.
C# Code
private static void ReadNameValueSectionHandler()
{
 Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);            
 NameValueCollection scriptFiles = (NameValueCollection)ConfigurationManager.GetSection(config.GetSection("scriptfiles").SectionInformation.SectionName);
 foreach (var item in scriptFiles.AllKeys)
 {
  Console.WriteLine(String.Format("Key:{0}, value:{1}", item, scriptFiles[item]));
 }
}
For the element with AppSettingsSection type we simply cast the ConfigurationSection object to AppSettingsSection.
C# Code
private static void ReadAppSettingsSection()
{
 Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
 ConfigurationSection section = config.GetSection("docfiles");
 var scriptSettings = ((AppSettingsSection)section).Settings;    

 foreach (var item in scriptSettings.AllKeys)
 {
  Console.WriteLine(String.Format("Key:{0}, value:{1}", item, scriptSettings[item].Value));
 }
}