Software Gardening

.NET, web, community, architecture, practices

The #1 thing you can do to improve code quality

Quality control

Yesterday I spoke at Utah Code Camp. The presentation is named “Healthy Code, Happy Code”. In this session, I discuss things you can do to ensure your code is healthy, other than running it.

Today I came across the results of a survey done by Smart Bear Software, a company that sells software for conducting code reviews. The survey, conducted earlier this year, had input from over 600 software professionals across 30 industries.

One question was “What do you believe is the number one thing a company can do to improve code quality?” 27.4 % of respondents said Code Reviews. In second place was Unit Testing with 18.7%.

Further, 90% said that the biggest benefit of code reviews was improved software quality.

This data reinforces the important point I make in the presentation. I’ll be incorporating the survey results for the next time I do this presentation next month at Nebraska.Code.

There are more interesting results in the survey. Check them out. And happy code reviews.

CodeMashed!

This week I’m at my first CodeMash. Yes, it’s 10 years in and I’ve heard great things over the years about this conference. I finally made it. And it was great! As any con, I reconnected with old friends, reconnected with longtime friends, and made new friends. The tech content was really, really top notch.

I was lucky enough to speak on Software Gardening. If you were at my session, thank you for being there. Here are the slides (PDF).

Your First ASP.NET 5 Application

ASP.Net 5 is a major change to the Microsoft web development ecosystem. As I write this, Release Candidate 1 is the current version available. You can expect some minor changes to things, but it’s quite baked at this point. Much of what you know about ASP.Net will need to be relearned. The changes bring ASP.Net more on par with the rest of the web development world.

There are several changes you need to know about. First, WebForms are gone. Everything is now MVC-based. Also, web controllers and Web API are now combined. VB is not supported. Another big change is that you can develop ASP.NET web applications on Windows via Visual Studio or on Windows, Mac, or Linux using Visual Studio Code. You can also run your site on Windows, Mac, or Linux thanks to the .NET Execution Environment (DNX).NET Core, and the new Kestrel server. You can still host on Windows Server in IIS or your Windows developer machine with IIS Express.

One big change is the removal of System.Web. Over the years, as new ASP.NET features have been added, they have been put in this assembly. It had become bloated. Many features were no longer used in modern web apps. And because of the bloat, it used a lot of memory. Everything is now modular and excluded by default.

Creating the project

But, let’s get on with what this post is about…creating your first web application with the new tooling.

  1. Install ASP.NET 5. Instructions for Windows, Mac, and Linux are here. Even if you are running Visual Studio 2015, you will need to get the latest bits. This walk through uses VS 2015 on Windows.
  2. From the VS menu, select File > New > Project.
  3. In the New Project Dialog, select Visual C# > Web. Make sure .NET Framework 4.6 is selected then choose ASP.Net Web Application. image
  4. Select OK to save your selected options and display the New ASP.Net Project dialog.
    image
  5. Under ASP.NET 5 Templates, select Web Application. Click OK to create the project. Visual Studio will work for a bit, then you’ll see the new project. But it looks different than you’re used to.
    image

You should now have a new ASP.NET 5 project, ready to use.

Understanding the project changes

Let’s pause for a moment to talk about these changes.

  • The src folder – This is the source folder. All the files needed to compile and build your web application.
  • What happened to .csproj? The project file is a Visual Studio file. Because Visual Studio doesn’t run on Mac or Linux, it has been removed and replaced with project.json. If you open this file you’ll see a list of dependencies, runtimes, scripts, and other files and settings.
  • Frameworks listed in project.json – Support of non-Windows platforms requires changes to the .NET runtime (CLR). The dnx451 is the full “Dot NET eXecution Environment”. Think of this as the full Windows runtime. To run on Mac, Linux, or even a reduced instruction set on Windows, use dnxcore50.
  • project.lock.json – This file contains a complete list of all the NuGet packages used in the project. In ASP.Net 5, only .Net assemblies are installed via NuGet. Javascript, css, html, and other types of files are installed and managed through a different mechanism explained in a moment.
  • wwwroot folder – Static files such as javascript, css, html, images, etc go here.
  • Dependencies folder – Non .NET dependencies are stored here and installed and managed via Bower, an open source dependency management tool that is used across platforms and web tooling. In other words, it’s NuGet for web front end packages.

    There is also an npm folder. This is the Node Package Manager. It’s the package manager for web backend packages.

  • global.json – Used by Visual Studio to store project information. Notice it sits outside the src folder.
  • appsettings.json – Application settings such as connection strings are put here.
  • gulp.js – Gulp is a widely used, open source build system. Think of this as being kind of like the old MSBuild file.
  • startup.cs – The entry point for your application.

Now that you know what the new files and folders are, it’s time to setup the database.

Creating the database

ASP.NET 5 uses Entity Framework 7 by default. The big change here is that the designer has been deprecated and is no longer available. It’s all EF Code First now.

You probably also noticed there is now a Models and View Models folder. For production systems, I move all the models to a Data project, but to make this introduction easier, I’ll leave the models in their current folder.

Open the appsettings.json file and you’ll see the connection string. As in earlier versions of ASP.NET MVC, localdb is used by default. I will leave these settings. I will also keep this introduction very simple by using a single table.

  1. Right-click on the Models folder and create a new class named Customer.
  2. Create the Customer class
       1: public class Customer

       2: {

       3:     public int Id { get; set; }

       4:     public string FirstName { get; set; }

       5:     public string LastName { get; set; }

       6:     public string Street1 { get; set; }

       7:     public string Street2 { get; set; }

       8:     public string City { get; set; }

       9:     public string State { get; set; }

      10:     public string ZipCode { get; set; }

      11: }

  3. Save the file
  4. Open the ApplicationDbContext.cs file and add a DbSet line for the Customer class.
       1: public class ApplicationDbContext : IdentityDbContext<ApplicationUser>

       2: {

       3:     protected override void OnModelCreating(ModelBuilder builder)

       4:     {

       5:         base.OnModelCreating(builder);

       6:         // Customize the ASP.NET Identity model and override the defaults if needed.

       7:         // For example, you can rename the ASP.NET Identity table names and more.

       8:         // Add your customizations after calling base.OnModelCreating(builder);

       9:     }

      10:  

      11:     public DbSet<Customer> Customers { get; set; }

      12: }

  5. Save the updated file.

The database will be created on first use. For now, we’ll move on to creating the forms.

The Customer Controller

Creating the Customer Controller is quite easy. We’ll use MVC scaffolding to do it.

  1. Right-click on the Controllers folder and select Add –> Controller. The Add Scaffold dialog is displayed.
    image
  2. Select MVC 6 Controller with views, using Entity Framework. Then click Add. The Add Controller dialog is displayed.
    image
  3. For Model class, select the Customer model.
  4. Next select the Data context class, ApplicationDbContext.
  5. Click Use async controller actions. Using async controllers is a good idea as it makes your application perform better.
  6. Click Add to create the CustomersController and views.

Open CustomersController.cs and you will see something new.

   1: public class CustomersController : Controller

   2: {

   3:     private ApplicationDbContext _context;

   4:  

   5:     public CustomersController(ApplicationDbContext context)

   6:     {

   7:         _context = context;    

   8:     }

   9:  

  10:     // GET: Customers

  11:     public async Task<IActionResult> Index()

  12:     {

  13:         return View(await _context.Customers.ToListAsync());

  14:     }

  15:  

  16:     // GET: Customers/Details/5

  17:     public async Task<IActionResult> Details(int? id)

  18:     {

  19:         if (id == null)

  20:         {

  21:             return HttpNotFound();

  22:         }

  23:  

  24:         Customer customer = await _context.Customers.SingleAsync(m => m.Id == id);

  25:         if (customer == null)

  26:         {

  27:             return HttpNotFound();

  28:         }

  29:  

  30:         return View(customer);

  31:     }

  32:  

  33:     // GET: Customers/Create

  34:     public IActionResult Create()

  35:     {

  36:         return View();

  37:     }

  38:  

  39:     // POST: Customers/Create

  40:     [HttpPost]

  41:     [ValidateAntiForgeryToken]

  42:     public async Task<IActionResult> Create(Customer customer)

  43:     {

  44:         if (ModelState.IsValid)

  45:         {

  46:             _context.Customers.Add(customer);

  47:             await _context.SaveChangesAsync();

  48:             return RedirectToAction("Index");

  49:         }

  50:         return View(customer);

  51:     }

  52:  

  53:     // GET: Customers/Edit/5

  54:     public async Task<IActionResult> Edit(int? id)

  55:     {

  56:         if (id == null)

  57:         {

  58:             return HttpNotFound();

  59:         }

  60:  

  61:         Customer customer = await _context.Customers.SingleAsync(m => m.Id == id);

  62:         if (customer == null)

  63:         {

  64:             return HttpNotFound();

  65:         }

  66:         return View(customer);

  67:     }

  68:  

  69:     // POST: Customers/Edit/5

  70:     [HttpPost]

  71:     [ValidateAntiForgeryToken]

  72:     public async Task<IActionResult> Edit(Customer customer)

  73:     {

  74:         if (ModelState.IsValid)

  75:         {

  76:             _context.Update(customer);

  77:             await _context.SaveChangesAsync();

  78:             return RedirectToAction("Index");

  79:         }

  80:         return View(customer);

  81:     }

  82:  

  83:     // GET: Customers/Delete/5

  84:     [ActionName("Delete")]

  85:     public async Task<IActionResult> Delete(int? id)

  86:     {

  87:         if (id == null)

  88:         {

  89:             return HttpNotFound();

  90:         }

  91:  

  92:         Customer customer = await _context.Customers.SingleAsync(m => m.Id == id);

  93:         if (customer == null)

  94:         {

  95:             return HttpNotFound();

  96:         }

  97:  

  98:         return View(customer);

  99:     }

 100:  

 101:     // POST: Customers/Delete/5

 102:     [HttpPost, ActionName("Delete")]

 103:     [ValidateAntiForgeryToken]

 104:     public async Task<IActionResult> DeleteConfirmed(int id)

 105:     {

 106:         Customer customer = await _context.Customers.SingleAsync(m => m.Id == id);

 107:         _context.Customers.Remove(customer);

 108:         await _context.SaveChangesAsync();

 109:         return RedirectToAction("Index");

 110:     }

 111: }

Notice the constructor beginning at line 5. The context is passed in rather than being created in the controller as it was in MVC 5. The big change MVC 6 is that Dependency Injection (DI) is used throughout. By default a simple DI system is used. But you can replace it with your favorite DI tool.

What happened to Razor?

If you created ASP.NET 5 forms, you were used to working with Razor syntax that looked something like this:

   1: @model Dashboard.Models.RegisterViewModel

   2: @{

   3:     ViewBag.Title = "Register";

   4: }

   5:  

   6: <h2>@ViewBag.Title.</h2>

   7:  

   8: @using (Html.BeginForm("Register", "Account", FormMethod.Post, new { @class = "form-horizontal", role = "form" }))

   9: {

  10:     @Html.AntiForgeryToken()

  11:     <h4>Create a new account.</h4>

  12:     <hr />

  13:     @Html.ValidationSummary("", new { @class = "text-danger" })

  14:     <div class="form-group">

  15:         @Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" })

  16:         <div class="col-md-10">

  17:             @Html.TextBoxFor(m => m.Email, new { @class = "form-control" })

  18:         </div>

  19:     </div>

  20:     <div class="form-group">

  21:         @Html.LabelFor(m => m.Password, new { @class = "col-md-2 control-label" })

  22:         <div class="col-md-10">

  23:             @Html.PasswordFor(m => m.Password, new { @class = "form-control" })

  24:         </div>

  25:     </div>

  26:     <div class="form-group">

  27:         @Html.LabelFor(m => m.ConfirmPassword, new { @class = "col-md-2 control-label" })

  28:         <div class="col-md-10">

  29:             @Html.PasswordFor(m => m.ConfirmPassword, new { @class = "form-control" })

  30:         </div>

  31:     </div>

  32:     <div class="form-group">

  33:         <div class="col-md-offset-2 col-md-10">

  34:             <input type="submit" class="btn btn-default" value="Register" />

  35:         </div>

  36:     </div>

  37: }

This code is used to create the Register form. Razor syntax is the @Html code. In ASP.NET 5 and MVC 6, Razor syntax has been replaced with “Tag Helpers”. Here’s the ASP.NET 5 version of Register.cshtml.

   1: @model RegisterViewModel

   2: @{

   3:     ViewData["Title"] = "Register";

   4: }

   5:  

   6: <h2>@ViewData["Title"].</h2>

   7:  

   8: <form asp-controller="Account" asp-action="Register" method="post" class="form-horizontal" role="form">

   9:     <h4>Create a new account.</h4>

  10:     <hr />

  11:     <div asp-validation-summary="ValidationSummary.All" class="text-danger"></div>

  12:     <div class="form-group">

  13:         <label asp-for="Email" class="col-md-2 control-label"></label>

  14:         <div class="col-md-10">

  15:             <input asp-for="Email" class="form-control" />

  16:             <span asp-validation-for="Email" class="text-danger"></span>

  17:         </div>

  18:     </div>

  19:     <div class="form-group">

  20:         <label asp-for="Password" class="col-md-2 control-label"></label>

  21:         <div class="col-md-10">

  22:             <input asp-for="Password" class="form-control" />

  23:             <span asp-validation-for="Password" class="text-danger"></span>

  24:         </div>

  25:     </div>

  26:     <div class="form-group">

  27:         <label asp-for="ConfirmPassword" class="col-md-2 control-label"></label>

  28:         <div class="col-md-10">

  29:             <input asp-for="ConfirmPassword" class="form-control" />

  30:             <span asp-validation-for="ConfirmPassword" class="text-danger"></span>

  31:         </div>

  32:     </div>

  33:     <div class="form-group">

  34:         <div class="col-md-offset-2 col-md-10">

  35:             <button type="submit" class="btn btn-default">Register</button>

  36:         </div>

  37:     </div>

  38: </form>

  39:  

  40: @section Scripts {

  41:     @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }

  42: }

Tag Helpers are the asp- construct inside the HTML tags. This makes ASP.NET 5 look more like other HTML and Javascript libraries. It makes the code look more like HTML. Open the Customer Create.cshtml to see with it looks like in this new version.

   1: @model WebApplication2.Models.Customer

   2:  

   3: @{

   4:     ViewData["Title"] = "Create";

   5: }

   6:  

   7: <h2>Create</h2>

   8:  

   9: <form asp-action="Create">

  10:     <div class="form-horizontal">

  11:         <h4>Customer</h4>

  12:         <hr />

  13:         <div asp-validation-summary="ValidationSummary.ModelOnly" class="text-danger"></div>

  14:         <div class="form-group">

  15:             <label asp-for="City" class="col-md-2 control-label"></label>

  16:             <div class="col-md-10">

  17:                 <input asp-for="City" class="form-control" />

  18:                 <span asp-validation-for="City" class="text-danger" />

  19:             </div>

  20:         </div>

  21:         <div class="form-group">

  22:             <label asp-for="FirstName" class="col-md-2 control-label"></label>

  23:             <div class="col-md-10">

  24:                 <input asp-for="FirstName" class="form-control" />

  25:                 <span asp-validation-for="FirstName" class="text-danger" />

  26:             </div>

  27:         </div>

  28:         <div class="form-group">

  29:             <label asp-for="LastName" class="col-md-2 control-label"></label>

  30:             <div class="col-md-10">

  31:                 <input asp-for="LastName" class="form-control" />

  32:                 <span asp-validation-for="LastName" class="text-danger" />

  33:             </div>

  34:         </div>

  35:         <div class="form-group">

  36:             <label asp-for="State" class="col-md-2 control-label"></label>

  37:             <div class="col-md-10">

  38:                 <input asp-for="State" class="form-control" />

  39:                 <span asp-validation-for="State" class="text-danger" />

  40:             </div>

  41:         </div>

  42:         <div class="form-group">

  43:             <label asp-for="Street1" class="col-md-2 control-label"></label>

  44:             <div class="col-md-10">

  45:                 <input asp-for="Street1" class="form-control" />

  46:                 <span asp-validation-for="Street1" class="text-danger" />

  47:             </div>

  48:         </div>

  49:         <div class="form-group">

  50:             <label asp-for="Street2" class="col-md-2 control-label"></label>

  51:             <div class="col-md-10">

  52:                 <input asp-for="Street2" class="form-control" />

  53:                 <span asp-validation-for="Street2" class="text-danger" />

  54:             </div>

  55:         </div>

  56:         <div class="form-group">

  57:             <label asp-for="ZipCode" class="col-md-2 control-label"></label>

  58:             <div class="col-md-10">

  59:                 <input asp-for="ZipCode" class="form-control" />

  60:                 <span asp-validation-for="ZipCode" class="text-danger" />

  61:             </div>

  62:         </div>

  63:         <div class="form-group">

  64:             <div class="col-md-offset-2 col-md-10">

  65:                 <input type="submit" value="Create" class="btn btn-default" />

  66:             </div>

  67:         </div>

  68:     </div>

  69: </form>

  70:  

  71: <div>

  72:     <a asp-action="Index">Back to List</a>

  73: </div>

  74:  

  75: @section Scripts {

  76:     <script src="~/lib/jquery/dist/jquery.min.js"></script>

  77:     <script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>

  78:     <script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>

  79: }

As you probably guessed, it is cleaner and easier to read than MVC 5.

Update the menu

Before we run the application, let’s add a menu item for Customers.

  1. Open _Layout.cshtml in the Views\Shared folder.
  2. Add a Customers menu item. Make sure you use a new Tag Helper. See line 5 below.
       1: <ul class="nav navbar-nav">

       2:     <li><a asp-controller="Home" asp-action="Index">Home</a></li>

       3:     <li><a asp-controller="Home" asp-action="About">About</a></li>

       4:     <li><a asp-controller="Home" asp-action="Contact">Contact</a></li>

       5:     <li><a asp-controller="Customers" asp-action="Index">Customers</a></li>

       6: </ul>

Now you’re ready to run the application. Press F5 to compile and run. Then navigate to the Customers Index page. If you get an error screen about Database errors, follow the instructions on the error page. Once things are up and running, try adding a few customer records.

Startup.cs

Before wrapping up, I need to tell you about startup.cs. This is the entry point to the application.  It’s important you know about this file because in ASP.NET 5, everything is turned off by default, even static pages (see line 73 below where static pages are enabled).

   1: public class Startup

   2: {

   3:     public Startup(IHostingEnvironment env)

   4:     {

   5:         // Set up configuration sources.

   6:         var builder = new ConfigurationBuilder()

   7:             .AddJsonFile("appsettings.json")

   8:             .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);

   9:  

  10:         if (env.IsDevelopment())

  11:         {

  12:             // For more details on using the user secret store see http://go.microsoft.com/fwlink/?LinkID=532709

  13:             builder.AddUserSecrets();

  14:         }

  15:  

  16:         builder.AddEnvironmentVariables();

  17:         Configuration = builder.Build();

  18:     }

  19:  

  20:     public IConfigurationRoot Configuration { get; set; }

  21:  

  22:     // This method gets called by the runtime. Use this method to add services to the container.

  23:     public void ConfigureServices(IServiceCollection services)

  24:     {

  25:         // Add framework services.

  26:         services.AddEntityFramework()

  27:             .AddSqlServer()

  28:             .AddDbContext<ApplicationDbContext>(options =>

  29:                 options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]));

  30:  

  31:         services.AddIdentity<ApplicationUser, IdentityRole>()

  32:             .AddEntityFrameworkStores<ApplicationDbContext>()

  33:             .AddDefaultTokenProviders();

  34:  

  35:         services.AddMvc();

  36:  

  37:         // Add application services.

  38:         services.AddTransient<IEmailSender, AuthMessageSender>();

  39:         services.AddTransient<ISmsSender, AuthMessageSender>();

  40:     }

  41:  

  42:     // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.

  43:     public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)

  44:     {

  45:         loggerFactory.AddConsole(Configuration.GetSection("Logging"));

  46:         loggerFactory.AddDebug();

  47:  

  48:         if (env.IsDevelopment())

  49:         {

  50:             app.UseBrowserLink();

  51:             app.UseDeveloperExceptionPage();

  52:             app.UseDatabaseErrorPage();

  53:         }

  54:         else

  55:         {

  56:             app.UseExceptionHandler("/Home/Error");

  57:  

  58:             // For more details on creating database during deployment see http://go.microsoft.com/fwlink/?LinkID=615859

  59:             try

  60:             {

  61:                 using (var serviceScope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>()

  62:                     .CreateScope())

  63:                 {

  64:                     serviceScope.ServiceProvider.GetService<ApplicationDbContext>()

  65:                             .Database.Migrate();

  66:                 }

  67:             }

  68:             catch { }

  69:         }

  70:  

  71:         app.UseIISPlatformHandler(options => options.AuthenticationDescriptions.Clear());

  72:  

  73:         app.UseStaticFiles();

  74:  

  75:         app.UseIdentity();

  76:  

  77:         // To configure external authentication please see http://go.microsoft.com/fwlink/?LinkID=532715

  78:  

  79:         app.UseMvc(routes =>

  80:         {

  81:             routes.MapRoute(

  82:                 name: "default",

  83:                 template: "{controller=Home}/{action=Index}/{id?}");

  84:         });

  85:     }

  86:  

  87:     // Entry point for the application.

  88:     public static void Main(string[] args) => WebApplication.Run<Startup>(args);

  89: }

The ASP.NET has done a good job of explaining this file here.

Wrap up

There is A LOT of new to learn about ASP.NET 5 and MVC 6. As I’m writing this, almost everything is documented at http://docs.asp.net. If you see a topic with a wrench icon next to it, there is still work to be done on that section.

If you’re thinking of migrating and MVC 5 application, make sure you read this post by my friend Paul Litwin where he goes through a migration step by step.

A Trick All Tech Presenters Should Know

I’m sitting here at the Microsoft MVP Summit this week and watching many presenters do the same thing. The sad thing, these are all Microsoft employees, many with polished decks. Here’s what they do:

  1. Launch PowerPoint
  2. Open the presentation
  3. Click the Slide Show button in PowerPoint
  4. Talk a bit using slides
  5. Press Escape to stop Slide Show mode. This returns PowerPoint to Design mode. Some even said something like, “I guess now you know what’s coming up” when we all can see upcoming slides
  6. Click a button on the Windows or Mac toolbar or launch Visual Studio or some other application
  7. Do the demo
  8. Go back to PowerPoint
  9. Click the Slide Show button
  10. Lather, Rinse, Repeat
  11. Lather, Rinse, Repeat
  12. Lather, Rinse, Repeat

In other words, they do this over and over again during their presentation. Why? Why do they do this? One reason is once you launch PowerPoint and then into Slide Show mode, there are two instances of PowerPoint running. If you Alt+Tab, you can see them, and the presenter gets confused about which one to activate when they want to go back to slides. The biggest reason is, they don’t know there’s a better way.

The first thing presenters need to remember is DO NOT LAUNCH POWERPOINT. Instead, open File Explorer. Navigate to your slide deck. Right-click. Select Show. Now, the deck will be launched in Slide Show mode and there is only one instance of PowerPoint running. When you want to go to your demo just Alt+Tab or hit the Windows key to bring up the Task Bar.

One word of caution. Do not hit Escape when in Slide Show mode because it will actually shutdown the slide show.

Utah Code Camp 2015

Yesterday I had the opportunity to attend Utah Code Camp. As I live in Salt Lake City, it was kind of like camping out in your backyard. It was great to catch up with old friends and make new ones.

The past few years I was one of the organizers of this camp, but this year I decided to step back. I will admit, it was good not having to keep things running and just be able to attend. I haven’t heard final attendance numbers, but Friday night, they were expecting between 600 and 700. That’s down from last year, but that was expected.UtahCodeCampVia@mgerickson

My session was right before lunch. The title was “A Little Non-chat About SignalR”. The idea came from my observation that most SignalR articles and demos show you how to create a chat app. I wanted something more realistic, that you would actually use in a real application. I have an application in production that uses progress bars and notifications, so it was a no-brainer to show how to do those. The other demo shows real-time data updates from one application to another.
UtahCodeCampVia@JoeMayo

Despite some pretty serious hardware issues and trouble with the projector, we got through everything and I think those of you who remained to end saw just how easy SignalR is. The demo code and slides are now available.

Thanks to @JoeMayo and @mgerickson for the pics.

I’ll be back next year. After all, it is my backyard. My next stop is Boise Camp Camp on March 21.

March Code Camps

I’ll be speaking at two upcoming Code Camps. The first is Utah Code Camp on March 14 in Salt Lake City. The other is Boise Code Camp the following week, March 21.

My topic at both camps is “A Little Non-Chat About SignalR”. Here’s the description: Web applications typically work by the browser sending a request to the server. But what if you need the server to send a request to the browser? SignalR will let you do that. But, it seems like every SignalR demo shows how to develop a chat application. How many of us are going to do that? In this session, we’ll explore real world uses for SignalR, including thermometers for long-running server tasks, alerts, SignalR in non-web apps, and more.

I hope to see you at one or both events.

Las Vegas Code Camp

I’m breaking a rule. What happens in Vegas doesn’t always stay in Vegas.

Yesterday was the first every Las Vegas Code Camp. You always expect bumps for a first time every camp. There were some things, but I think they were small. The organizers did a great job for a first ever camp. If I were to give out grades on the camp, here’s what they’d be: Networking: A, Sessions: A, Food A+++ (it wasn’t pizza). Those are the three things to look for in a code camp.

My session, “Software Gardening” was in the second time slot of the day. Thank you for attending. I heard some very good feedback, including one long-time, well-known .Net developer who told me the part about Katas made him think about their importance. Here is my slide deck.

I hope to make it back next year for a second Las Vegas Code Camp.

Ajax modal forms in ASP.Net MVC

I’m working on a project where the Bootstrap modal dialog is being used to popup data entry and other forms. I had it working using jQuery to handle the Ajax call to the Controller. It was a lot of work to gather the form data into the JSON packet, call the Controller and handle the return values, especially if the form did not pass validation.

address

I thought there had to be better way.  Here are the requirements I had:

  • The Bootstrap dialog must be modal
  • The form should not be loaded into the browser with the page. It will be read from the server when needed and then displayed.
  • The data must be sent via Ajax to the server.
  • If possible, validation should be performed client-side, before sending data to the server.
  • The form should stay open if Model Validation fails and validation messages should be displayed.

I did what any good developer does…I hit a search engine and found several articles that I had to piece together to make it all work. The process is quite simple:

  1. An Ajax request is sent from the browser.
  2. The server returns a partial view to the browser.
  3. Javascript code receives the form and it is placed as HTML into a specified div.
  4. The form is displayed.
  5. When the user clicks Save, the form data is sent to the Controller, just as any form data but with one exception…it’s sent as Ajax.
  6. The Controller method validates the data. If it passes validation, the data is saved, a success message is sent back to the server and displayed to the user, then the form is closed. If the data fails validation, it is returned to the form and the validation messages are displayed.

First, I had to setup the initial request. I put an empty div in the _Layout.cshtml file. This way, I can display dialogs from anywhere in the application.

<body class="dashboard" style="padding-top: 0px;">
        <div id="dialogPlaceholder"></div>
… remaining body code
</body>

Next, I placed an New Address button on the CompanyDetails form and set its click event to call the Javascript that loads the AddEdit form.

function openAddressDialog(id) {
    var data = {
        Id: id,
        CompanyId: $('#Id').val()
    };
    $.ajax({
        url: '/crm/customer/AddEditAddress/',
        contentType: 'application/html',
        data: data,
        success: function(content) {
            $('#dialogPlaceholder').html(content);
        },
        error: function(e) {}
    });        
}

The controller loads up the Model and returns the partial view. The form code is like any other form except that you make it an Ajax form.

@model Models.AddEditAddress

<div id="dialogResult"></div>

@using (Ajax.BeginForm("SaveAddressAjax", "shared", new AjaxOptions
{
    HttpMethod = "POST",
    InsertionMode = InsertionMode.Replace,
    OnSuccess = "updateAddressSuccess()",
    OnFailure = "dialogFailure()",
    OnBegin = "dialogBegin()",
    OnComplete = "dialogComplete()",
    UpdateTargetId = "dialogResult"
}))
{
… Rest of form code goes here.
} <script src="~/Scripts/jquery.unobtrusive-ajax.min.js"></script> <script src="~/Scripts/genericDialog.js"></script> <script> $(document).ready(function() { $('#addEditAddressDialog').modal(); });




function updateAddressSuccess() { $('#addEditAddressDialog').modal("hide"); } </script>

Look at the Ajax.BeginForm statement OnSuccess, OnFailure, OnBegin, OnComplete define Javascript functions that run when the specified event occurs. I created dummy methods that do nothing and placed them in genericDialog.js. Then, I can override each one, simply by providing a different Javascript function, for example updateAddressSuccess.

// genericDialog.js
function dialogSuccess() {}
function dialogFailure() {}
function dialogBegin() {}
function dialogComplete() {}

And that’s all there is to it. A simple dialog that is loaded on-demand. You can also use the same methodology to load ANY partial view on demand. For example, you may have a complex form with multiple tabs and only load the tab data when the user clicks on it. Finally, you can use this method to make your forms seem faster. Because you won’t have to load up everything in the form, it gets generated faster and less data is sent to the browser on initial load, making the application seem faster. Your users will thank you.

The annual email

mvplogoFour times a year, Microsoft sends out email announcements letting people know they have been awarded the Microsoft Most Valuable Professional (MVP). I look for this email to arrive on October 1. I’m humbled to say, I have been named an MVP for the 19th year. My original award was for FoxPro and now for Visual C#.

The MVP is given to people for providing community support. It can be through conference speaking, magazines, blogs, books, forum posts, etc. With about 4000 MVPs worldwide, just about every Microsoft product is covered. Recently, Microsoft started to give the award to supporters of open source projects.

One of the highlights of being an MVP is the annual MVP Summit. It’s three intense days meeting directly with Microsoft teams in Redmond. It’s a give and take where we get to discuss issues with Microsoft products and where we hope to see them go. The Microsoft teams also share their vision for the products. Because sessions are under a Non-disclosure Agreement (NDA), discussions are open and candid. This year the Summit will be the first week of November and highlighted with a visit from new Microsoft CEO Satya Nadella.

Thank you Microsoft for again giving me this award and thank you, community, for allowing me to visit your events and reading my column in DNC Magazine. I hope to see you at an event soon.

 

Summer Speaking Gigs

I have a couple of speaking gigs scheduled this summer.

First, I’ll be at Denver Dev Day on June 14. This is a 1/2 day event on ASP.Net. There will be two sessions during the day, so sign up for either the DenverDevDaymorning or the afternoon. My presentation will be Unit Testing ASP.Net MVC. This is a topic I’ve been doing for a year or so now, but I have some new material that I will present for the first time in Denver.

Second, I’m excited to be returning to DevLink. The first time I attended, DevLink was in Nashville. It’s now held in Chatanooga. devlinkThis year it runs August 27-29. I am preparing a new presentation, “Continuous Integration with TeamCity”. Here’s the synopsis:

In a good development process you check in your code often, sometimes multiple times per day. But what happens to that code once you’ve checked it in? With Continuous Integration or CI, that code is pulled from version control, compiled, unit tested, and more. In this session you will learn how to do CI with Team City. You’ll see how to configure Team City to do a complete build and test of your code and provide feedback to the team. You will learn – What is Continuous Integration and why should you care – How to configure Team City to pull code from version control – The difference between integration, daily, weekly, and other builds – What are artifacts and where they are stored – How to get feedback to your team.

I use TeamCity daily at work and am currently setting up Continuous Delivery with it. I don’t think I’ll have to get that far in this presentation, but if I touch on it, I will.

I hope to see you at one of these events.

Source: CraigBerntson

« Older posts

© 2017 Software Gardening

Theme by Anders NorenUp ↑