Mason's Blog

Release of FancyStoreDemo and SharpNoty

4/1/2015 6:28:54 PM

I was inspired by a question I saw on Stack Overflow. The asker either wanted to put database code in their Web Forms page code behind, or to embed it in their model. Both of which are wrong. If you sprinkle data access code in your code behind, then need to make a schema change, you'll have to update a bunch of places. That's not very user friendly. Plus, you end up repeating yourself to save and retrieve the same objects over and over, violating the DRY principle. Putting it in the model is a little better, because at least now you're not repeating yourself. But it ties the model to your database, which is not a good thing. Now that same model class can't be used if you want to start using it a desktop WPF client application, or a Xamarin mobile application. That's not good.

So of course, the solution is to have a separate data layer responsible for database access. This should come in the form of an interface that defines the communication to be done between the application and the database, and concrete classes that implement the interface and do the actual communication with the database. The application should not specifically know about those concrete classes, except in a single configuration step. Instead, it should use a dependency injection framework (or at least static helper classes) to pass that information back and forth.

It's a little hard to understand all these concepts, especially if you're new to programming or you've never been taught the right way (I never was, had to learn it myself). Which is why I created a demo application that shows these concepts. Since I'm unoriginal, I went with the web store concept and called it FancyStoreDemo. It shows an extremely simple web site that can use various databases depending on what's been selected in the configuration file. I've implemented providers for various databases (and flat files), which also makes it a good way to learn about other databases that you may be unfamiliar with. What's more, I've open sourced the project on GitHub if you want to improve the application (I have no idea what I'm doing with Redis).

I haven't done a whole lot of public sites, most of what I've done has been internal web applications for the company I'm employed at. But I needed a way in FancyStoreDemo to easily provide pop up notifications on the client side letting them know when certain actions have been taken. I've used noty for this in the past, a nice looking client side library for creating "toast" style messages to the user. But it's difficult to write JavaScript from the server side, you don't get Intellisense or any sort of compilation checking to make sure what you've written won't result in a client side error. The worst part is writing JavaScript as a string embedded in C# (or VB.NET).

In order to resolve that problem, I took some code I used at my day job and turned it into SharpNoty. SharpNoty makes it easy to define server side notifications in Web Forms (MVC support is planned). What used to look like this to create a noty:

ClientScript.RegisterStartupScript(this.GetType(), "uniquekey", "noty({text: 'Hello, world!', type: alert});");

has been abstracted to this:

Page.AddNoty(new Noty("Hello, world!", MessageType.alert));

Much nicer! Of course, this is just the beginning and I've only released the NuGet package so I could make use of it for FancyStoreDemo. There's still a lot of work to do. Feel free to look at it, try it out, and contribute!

Comments (0)

Future Topics

3/28/2015 6:34:31 AM

Some future topics I would like to write about include:

Comments (0)

How to resume a stopped activity (run) in RunKeeper

3/13/2015 3:37:39 PM

I use RunKeeper to keep track of my daily runs with my dog. I used to use Garmin and Forerunner 205 watch. But the watch would take a while to acquire a GPS signal, and I'd have to manually upload the results to the website. I switched several months ago to RunKeeper and a Moto 360 watch. That has worked great, my run gets uploaded to RunKeeper's site as soon as it's over. The RunKeeper app and website are fairly easy to use, and RunKeeper thoughtfully added Android Wear integration. I had contacted Garmin and told them to add Android Wear integration, but they ignored me so they lost my business.

I have run into one frustrating thing. When I have to pause for my dog to go potty or while we're waiting at a stop light, sometimes I accidentally hit Stop instead of Resume. And once you've stopped, you can't resume! Never fear, start a new activity (run) and finish your activity. When you get home, go to your computer and follow the below directions.

  1. Log into runkeeper.com

  2. Click on Me at the top.

  3. Click Activities at the top.

  4. Click the activity on the left.

  5. Scroll down and under Export click GPX

  6. Save the file to your computer.

  7. Repeat steps 4-6 for the other activity.

  8. Open the .gpx files up with a text editor such as Notepad. I prefer Notepad++.

  9. Each trkseg represents a contiguous portion of the activity (run). For example, if you never paused your activity, then you'd have only one trkseg. If you paused your activity halfway through, you'd have two trkseg's.

  10. Copy all the trkseg's for the second activity and paste them below the last trkseg in the prior activity.

  11. Save the results to a new file (it's best not to overwrite the originals in case you messed up).

  12. Go to RunKeeper's site and click New Activity, select your activity type and click next.

  13. On the map screen, click Upload Map. Click Choose File and upload your new GPX file. Click Next.

  14. Click Save

  15. Now you should have three activities. Two small ones, and then a big one that combines both of them. You can delete the two small ones from Run Keeper (you may need to delete it from your cell phone too so it doesn't re-upload, but mine did it automatically).

Comments (0)

Properly generating Excel files in .NET

3/1/2015 3:46:37 PM

I've seen a lot of new web developers struggle with generating Excel files in their web applications. They often take one of two incorrect approaches.

  1. Take a Gridview, render it to HTML, then send that to the client with an Excel MIME type and/or a .xls file extension.
  2. Use Office Interop.

The first approach often looks something like this:

protected void ExportBtn_Click(object sender, EventArgs e)
{
    Response.Clear();
    Response.AddHeader("content-disposition", "attachment;filename=myexcelfile.xls");
    Response.ContentType = "application/vnd.xls";
    StringWriter sw = new StringWriter();
    HtmlTextWriter htw = new HtmlTextWriter(sw);
    ResultGrid.RenderControl(htw);
    Response.Write(sw.ToString());
    Response.End();
}

This results in an HTML file being served to the client pretending to be a file that contains Excel data. But it isn't. So when opening this file in Microsoft Office on a desktop computer, it will display a warning that the file may be corrupted. The user can click past the warning, but that's not very user friendly or professional.

Excel Warning

Another downside to this approach is that any consuming application that doesn't know how to handle .xls files that contain HTML will report the file is corrupted and refuse to display anything at all, even if the application knows how to open HTML files with a .html extension. Often this approach is taken by someone who asks themselves "How can I export a GridView to Excel?" Which is not a good way of thinking about what you're trying to accomplish. Most of the time, the goal is to export the underlying data to Excel, not the GridView.

The Office Interop approach is even worse. Office Interop was not meant to be used on servers. It will cause plenty of strange errors. And the Office Interop libraries aren't friendly to work with. Don't use it. That's all I'm going to say about that approach.

The correct approach to providing Excel files to your user is to use a library capable of generating Open Office XML Spreadsheet (.xlsx) files natively. There's several libraries for this, such as Open Office XML SDK from Microsoft, NPOI (NuGet), or EPPlus (NuGet).

My favorite is EPPlus. Here's an example of creating a real .xlsx file from data in a DataTable.

protected void ExportBtn_Click(object sender, EventArgs e)
{
    Response.Clear();
    Response.AddHeader("content-disposition", "attachment;filename=myexcelfile.xlsx");
    Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
    var package = new ExcelPackage(); //create a new package, this is the equivalent of an XLSX file.
    var sheet = package.Workbook.Worksheets.Add("My Data"); //Add a new sheet to the workbook
    var dt = GetDataTable(); //This retrieves a System.Data.DataTable, you'd likely get it from your database.
    sheet.Cells["A1"].LoadFromDataTable(dt, true); //EPPlus contains helper function to load data from a DataTable, though you could manually fill in rows/column values yourself if you want
    Response.BinaryWrite(package.GetAsByteArray());
    Response.End();
}

You might be thinking "Okay, that got the data in there. But my Export GridView to HTML approach also included some styling info!". Which is true. Let's say we want to use an Excel table style.

protected void ExportBtn_Click(object sender, EventArgs e)
{
    Response.Clear();
    Response.AddHeader("content-disposition", "attachment;filename=myexcelfile.xlsx");
    Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
    var package = new ExcelPackage(); //create a new package, this is the equivalent of an XLSX file.
    var sheet = package.Workbook.Worksheets.Add("My Data"); //Add a new sheet to the workbook
    var dt = GetDataTable(); //This retrieves a System.Data.DataTable, you'd likely get it from your database.
    sheet.Cells["A1"].LoadFromDataTable(dt, true); //EPPlus contains helper function to load data from a DataTable, though you could manually fill in rows/column values yourself if you want
    var range = sheet.Cells[1, 1, dt.Rows.Count + 1, 2]; //We're getting a reference to all the cells that contain data
    var table = sheet.Tables.Add(range, "My Data Table"); //Creating an Excel table
    table.TableStyle = TableStyles.Medium8; //Setting the table style to something that looks nice
    range.AutoFitColumns(); //Auto fitting the column widths.
    Response.BinaryWrite(package.GetAsByteArray());
    Response.End();
}

Also, commonly among Web Forms developers (and less commonly among MVC developers), people generate their file directly in some code behind button event handler. You can take advantage of strongly typed models instead, and gain a bit more control over how your Excel file is generated.

public static ExcelPackage GenerateExcelFileForProducts(IEnumerable<Product> products)
{
    var package = new ExcelPackage();
    var sheet = package.Workbook.Worksheets.Add("Products");
    int rownum = 1;
    sheet.Cells["A" + rownum].Value = "Id";
    sheet.Cells["B" + rownum].Value = "Name";
    sheet.Cells["C" + rownum].Value = "Description";
    sheet.Cells["D" + rownum].Value = "Price";            
    foreach (var p in products)
        {
        rownum++;
        sheet.Cells["A" + rownum].Value = p.Id;
        sheet.Cells["B" + rownum].Value = p.Name;
        sheet.Cells["C" + rownum].Value = p.Description;
        sheet.Cells["D" + rownum].Value = p.Price;
        }
    var range = sheet.Cells[1, 1, rownum, 4];
    var table = sheet.Tables.Add(range, "Products Table");
    table.TableStyle = TableStyles.Medium8;
    range.AutoFitColumns();
    return package;
}

Some people don't like .xlsx files, because they believe that they're incompatible with Office 2003 and Office XP. That's partially true. Originally they did not support the Open Office XML formats. However, an available service pack provides support for the formats. You really have no excuse to be using .xls files anymore.

Comments (0)

Managing Dependencies in Libraries Used by Multiple Solutions

2/9/2015 10:50:00 PM

I saw a question on Stack Overflow a few months ago about how to manage dependencies in business applications that take a dependency on a common utility project. I was able to answer this question acceptably, so I decided I'd write a little bit more about it here. By the way, the reason I knew how to answer this was because I had run into the same problem before and posted a similar question on SO.

The problem arises when you create a utility library, for example to help with database calls or retrieving common heavily used data. You add it as a project to the solution, then create a project reference. That works well enough, but then you start work on a new solution. You naturally want to take advantage of your utility library again, so you add it as a project reference to that solution. And soon enough, your utilities are used by 15 different solutions. And now you're afraid to make a change to it, because you realize it might break other solutions. So now you're in dependency hell.

The problem arises from incorrectly thinking about the utility library. It should not be part of any other projects solution. It needs to be standalone, because it shouldn't need any knowledge of how it's being uses. Then, to make it so that you're not afraid to modify it, you need to use NuGet and versioning. I'm not going to go into how to set it up in this post, because there's plenty of good resources to get you started already out there. The beauty of this is that Solution X can use version 1.0.7 of your utilities, and Solution Y can use version 1.0.8. And then you can implement version 1.0.9 and introduce a breaking change without worrying about crippling your other app. At your leisure, you can still update to reference a newer library and then solve the breaking changes without feeling pressured, because you can always reference an older version of the library as you see fit.

Comments (0)

First Blog Entry and First Open Source Contribution

2/7/2015 11:00:00 PM

I worked all day on my site. I've added a basic blog feature and ASP.NET Identity and Thinktecture.IdentityManager to this site. It's been a very educational day for me. The blog was straight forward, I've done that before. Identity was a bit more difficult, but luckily you can just create a new web project in Visual Studio and use that as an example of how to set it up.

The real challenge today was getting Thinktecture.IdentityManager working. It's a tool for administering users and roles in an ASP.NET site. The beauty of it is that it's all self contained. There's no need to add a bunch of web pages or JavaScript or CSS. The configuration was a bit tricky, getting it to play nice with my Entity Framework DB Context (I'm still learning my way around EF).

The real disappointment was when I deployed to my web server and couldn't access the Identity Manager. IdentityManager is only set up to work with localhost or working with OAuth for accessing the admin interface. But that's no good, I want to be able to manage users on the web server without setting up OAuth. So I forked the project on GitHub, spent several hours making my changes and testing them, and finally ended up with a pull request. It hasn't been accepted yet. I'm sure I'll have done something wrong and need to fix it up. I'm still new to Git. I've used SVN a lot, but since I'm the only developer at my workplace, I haven't used any advanced features. And of course, Git is like SVN on steroids. So I ended up making an empty commit to my Git repository. I'm surprised it let me do that. I think it makes me look a little dumb. Oh well. Learnin. Coded from 7am to 11pm today. Short breaks for lunch and to play with the dog. Skipped dinner.

Comments (0)