Wednesday, June 27, 2018

A14–Building App using Angular and ASP.NET Core 2.1–Responsive Product Card and Shopping Cart

This post is a part of a series of posts that I am writing as I am building an app using Angular and ASP.NET Core 2.1. Links to previous posts –> A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13 Github Repo

Today’s post is again going to be brief. You might think that these posts are becoming boring and I don’t put more code. My goal is to work on this app just a little bit everyday and learn something everyday. I don’t get to spend a lot of time on this app since most of the time I am working late at night. Sometimes I might do a lot and sometimes not a whole lot. So my goal is just learn and share—even if it is one sentence that I watched a video.

I tried to make product card and shopping cart responsive. I added checkout-contact component and hooked up to checkout button. However, I didn’t implemented logic for collecting contact information. I am thinking of first completing entire navigation scenario of checkout process and then implement details of each page.

Alright that’s it. Checkout the code on github.

Tuesday, June 26, 2018

A13–Building App using Angular and ASP.NET Core 2.1–Updating Shopping Cart Quantity

This post is a part of a series of posts that I am writing as I am building an app using Angular and ASP.NET Core 2.1. Links to previous posts –> A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12 Github Repo

Today’s post is going to be brief. I added following functionality to Shopping Cart page.

When you increase quantity of any given product then,

1. Order sub total should get updated.

2. Order Quantity should be updated.

3. Cart total should be updated.

Since there is no database backend, I have to add extra logic to account for persistence. For example, to simulate accurate quantity and amount post deletion, I had to write custom server side logic. This is unnecessary once data store is in place.

image

After increasing quantity order sub total is updated.

image

There is one issue I am running into and that is when using ngModelChange on input element, the change event is firing twice which seems like bug to me or I am doing something wrong (I think later to be true).

That’s all for today, see ya next time.

Monday, June 25, 2018

A12–Building App using Angular and ASP.NET Core 2.1–Shopping Cart

This post is a part of a series of posts that I am writing as I am building an app using Angular and ASP.NET Core 2.1. Links to previous posts –> A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11 Github Repo

In the previous post, I started created Shopping Cart page where you could view products and remove products from Shopping Cart. Today, I want to fix a couple of things about Shopping Cart. If you added multiple products then we want to do following things.

1. Show Product along with quantity

2. Change Product quantity

3. Show Order Total

4. Update Order Total when product is deleted.

5. Do not show same product multiple times if product is ordered multiple times.

Below is the UI for new checkout experience.

image

If I remove product then order total is updated.

image

I created a complete different class for displaying products on Shopping Cart Page. I am calling it ShoppingCartProduct. In the ShoppingCartController, I am getting all products and then doing a group by into ShoppingCartProduct.

using A100.Models;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;

namespace A100.Controllers
{
    [Route("api/[controller]")]
    public class ShoppingCartController : Controller
    {
        private static List<Product> shoppingCartProducts = new List<Product>() {
            new Product { Id = 1, Title = "XYZ1",Description = "Description XYZ 1 ", Price = 101,ImageUrl = "ImageUrl_XYZ1" },
            new Product { Id = 1, Title = "XYZ1",Description = "Description XYZ 1 ", Price = 101,ImageUrl = "ImageUrl_XYZ1" },
            new Product { Id = 1, Title = "XYZ1",Description = "Description XYZ 1 ", Price = 101,ImageUrl = "ImageUrl_XYZ1" },
            new Product { Id = 2, Title = "XYZ2",Description = "Description XYZ 2 ", Price = 200,ImageUrl = "ImageUrl_XYZ2" }
        };
        [HttpGet("[action]")]
        public IEnumerable<ShoppingCartProduct> Products()
        {
            var s = from y in shoppingCartProducts
                    group y by y.Id into grouping
                    let p = grouping.First()
                    select new ShoppingCartProduct { Id = grouping.Key,
                        Title = p.Title,
                        Quantity = grouping.Count(),
                        Price = p.Price,
                        Description = p.Description,
                        ImageUrl = p.ImageUrl,
                        TotalPrice = p.Price * grouping.Count() };
            return s.ToList();
        }

        [HttpPost("[action]/{id:int}")]
        public ActionResult Add(int id)
        {
            return new JsonResult("product added to cart");
        }
        [HttpPost("[action]/{id:int}")]
        public ActionResult Delete(int id)
        {
            return new JsonResult("product removed from cart");
        }
    }
}

I had to update relevant parts shopping-cart.component.ts as well.

That’s all I have for today. Please check source code on Github and ask questions if you have any.

Friday, June 22, 2018

A11–Building App using Angular and ASP.NET Core 2.1–Services and Component Refactoring

This post is a part of a series of posts that I am writing as I am building an app using Angular and ASP.NET Core 2.1. Links to previous posts –> A1, A2, A3, A4, A5, A6, A7, A8, A9, A10 Github Repo

Yesterday, I added items to Shopping Cart and API to add products to Shopping Cart. Next step is to be able to checkout products from Shopping Cart and in order to do so I needed a page to display products in Shopping Cart. So Below are things, I was able to accomplish today.

1. Added Shopping Cart Component, Display Products in the cart, Remove products from Shopping Cart.

image

2. I added Shopping Module and Routing Module for that. Since after adding Shopping Module, I was running into issues related to ShoppingCartWidget component. NavMenu component was complaining that you have to declare in the main module. I moved ShoppingCartWidget component into Shared Folder and reference from there. I had to refactor little bit regarding that.

3. Added code to Shopping Service related to removing product from shopping cart.

There are couple of things, I wanted to share that I liked. I switch between VS Code and Visual Studio for this project and I am in love with VS Code. Today I installed few extensions for VS and it makes your job much easier. Below are the ones I use for Angular Development.

1. Angular 6 Snippets – Mikael Morlund

2. Angular Files – Alexander Ivanichev

3. Angular Language Service – Angular

4. Angular V6 Snippets – John Papa

5. Debugger for Chrome – Microsoft

6. TSLint – Egamma

7. SASS – Robin Bentley

Angular Language Service extension and snippets is by far my favorite one. But they all helped me a lot. VS Code is so light weight. I like it a lot.

On learning path I am intending on finishing below courses

1. Learning Angular Routing by Debora Kurata on Pluralsight

2. Implementing and Securing an API with ASP.NET Core by Shawn Wildermuth on Pluralsight

See ya next time. And leave comments if you like anything or have any suggestion.

Code on GitHub.

Thursday, June 21, 2018

A10–Building App using Angular and ASP.NET Core 2.1–Services, Events and Cross Component Communication

This post is a part of a series of posts that I am writing as I am building an app using Angular and ASP.NET Core 2.1. Links to previous posts –> A1, A2, A3, A4, A5, A6, A7, A8, A9 Github Repo
Today, I was able to accomplish few things,
1. Added Shopping service that adds product and updates shopping cart
2. Established cross component communication via Shopping Service (Home Component –> Add To Cart –> Updates Shopping Cart
3. Created API for adding and getting products from ShoppingCart Controller. I am returning hard coded products and hence you will always see two shown at the top right.
Right now I didn’t wanted to create any database backend. I want to just make sure client server interaction is in sync. Once I like how everything is structured then I will invest time into adding database layer. Below is code for Shopping Service.
import { Injectable, Inject } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Product } from '../product/product';
import { catchError, map, tap,last } from 'rxjs/operators';
import 'rxjs/add/observable/throw';
import { of } from 'rxjs/observable/of';
import { Observable } from 'rxjs/Observable';
const httpOptions = {
  headers: new HttpHeaders({
    'Content-Type': 'application/json'
  })
};
@Injectable()
export class ShoppingService {

  private _baseUrl: string;
  private cartQuantitySource = new BehaviorSubject(0);
  currentCartQuantity = this.cartQuantitySource.asObservable();

  private _addProductToShoppingCart: string = "api/ShoppingCart/Add/";
  private _getProductsFromShoppingCart: string = "api/ShoppingCart/Products";
  constructor(private _http: HttpClient, @Inject('BASE_URL') baseUrl: string) {
    this._baseUrl = baseUrl;
    this.updateCartQuantity(); 
  }

  updateCartQuantity() {
    this._http.get<Product[]>(this._baseUrl + this._getProductsFromShoppingCart).subscribe(products => {
      this.log(`getting products from shopping cart`);
      this.cartQuantitySource.next(products.length);
    });
  }

  addProductToCart(product: Product) {
    this._http.post(this._baseUrl + this._addProductToShoppingCart + product.id, product, httpOptions).subscribe(x => {
      this.log(`added Product To Shopping Cart`);
      this.updateCartQuantity();
    });    
  }

  private handleError<T>(operation = 'operation', result?: T) {
    return (error: any): Observable<T> => {
      console.log(error); //log to console instead       
      this.log(`${operation} failed: ${error.message}`);
      return Observable.throw(error || 'Server error');
    };
  }
  private log(message: string) {
    console.log("Shopping Service " + message);
  }
}

One of the things, I am not liking is how api urls are hard coded as strings. This is something I want to improve upon. I will put them inside an injectable service which has all the urls.
Next thing I want to learn is authentication and authorization with ASP.NET Core.

Wednesday, June 20, 2018

A9–Building App using Angular and ASP.NET Core 2.1–Font-awesome, Pagination and Layout

This post is a part of a series of posts that I am writing as I am building an app using Angular and ASP.NET Core 2.1. Links to previous posts –> A1, A2, A3, A4, A5, A6, A7, A8, Github Repo

Today, I got carried away with home page layout and wasn’t able to fix communication between components. I spent trying to add pagination using some blogpost but then I discovered ngx-pagination. Below are things I was able to do.

1. Added pagination using ngx-pagination npm package it was pretty straight forward

2. Added font-awesome npm package so I could add shopping cart icon.

3. Added pagination to home page and products page

4. Added shopping-cart-widget component for displaying cart information

image

Next, I want to fix communication between components, ie. when you click on add to cart button it should add items to cart and call server side api method.

See ya next time.

Tuesday, June 19, 2018

A8–Building App using Angular and ASP.NET Core 2.1–SASS and Responsive Layout

This post is a part of a series of posts that I am writing as I am building an app using Angular and ASP.NET Core 2.1. Links to previous posts –> A1, A2, A3, A4, A5, A6, A7, Github Repo

Today, I could accomplish very little.

1. Fixed cards layout for home page

I like to put borders and see how where the boxes are.

image

As we change screen size, we can see responsive design at work.

image

Another one

image

image

Alright I messed this one up, I want to make this look different. However, I am running out of time for today.

image

2. From the screenshots above, menu has been fixed and is also responsive.

3. Using SASS syntax was something new—you don’t have to put {} and ; and indentation like python. So I will have to get used to this syntax.

Next, I will have to continue fixing home page styling and then I will follow up on adding more product information. I am excited to work on server side logic.

See ya next time.

Monday, June 18, 2018

A7–Building App using Angular and ASP.NET Core 2.1–Bootstrap 4, SASS, Cleanup

This post is a part of a series of posts that I am writing as I am building an app using Angular and ASP.NET Core 2.1. Links to previous posts –> A1, A2, A3, A4, A5, A6, A7, Github Repo

On training side, I finished watching Beginner Path for Angular on Pluralsight. I learnt some nice things about Angular CLI. I didn’t knew that Angular app can be created using SASS, CSS or LESS as default way of creating style files. Dry run option is awesome. I always liked how PowerShell had –WhatIf flag and every CLI should have these types of commands.

Let’s cover all the things I was able to accomplish today.

1. Refactored app.module.ts file to make it leaner. I moved all product related components, routes and services into product module. In the image below, on the left everything in red was moved into product module.

image

2. Set the default style extension to be SASS and renamed all .css files to .sass. Right now I didn’t not create any styles into any sass file. Ahem, have to learn first right. Actually, I heard it is not very different than .less so will see how sass is. I had to delete navmenu component styles that were created by default template.

image

3. While I have worked with Bootstrap 3 a lot, I wanted to learn Bootstrap 4 in this project so I updated to Bootstrap 4. When you install Bootstrap 4 in an angular project, npm doesn’t install jquery, popper.js libraries so, I had to install those. I had to fix styling for home page and navigation to use Bootstrap 4.

image

4. Other visual and layout changes includes moving nav menu to top, moving home page content to about page, adding products to home page for people to view products on sale.

image

You can see home page with product cards. The UI is all messed up right now. There are many changes need to be made to how cards are displayed. The bottom card is completely hideous—taking up whole page.

image

5. Bug fix. In product.service.ts there was bug found in the handleError function which was returning default type. It should have thrown error. This prevented server side validation error from being displayed to our user.

image

So that’s all for today. The app is completely garbage right now but I am making progress. My next goals are as follows:

1. Make home page UI responsive, add style for product cards, make navigation menu responsive and add more data to display cards appropriately.

2. Add product description and other product related meta data, display that data accordingly on home page, add more complex data validation—using dates and dropdown.

See ya next time.

Friday, June 15, 2018

A6–Building App using Angular and ASP.NET Core 2.1– Cleanup, Host on Azure, CI and CD pipeline

This post is a part of a series of posts that I am writing as I am building an app using Angular and ASP.NET Core 2.1. Links to previous posts –> A1, A2, A3, A4, A5 Github Repo

Here what I was able to accomplish today.

1. Cleanup default files created by Project template

2. Write readme document

3. Create CI and CD Pipeline using VSTS

4. Host on Azure App Service using Free Tier (link).

image

Hosted web site can be found here.

image

Thursday, June 14, 2018

A5–Building App using Angular and ASP.NET Core 2.1 – Services Dependency Injection

This post is a part of a series of posts that I am writing as I am building an app using Angular and ASP.NET Core 2.1. Links to previous posts –> A1, A2, A3, A4, Github Repo

Today my goal is to extract httpclient into a product service. And finish delete page.

Below is the code for extracted ProductService.

import { Injectable, Inject } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Product } from './product';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { catchError, map, tap } from 'rxjs/operators';
import { of } from 'rxjs/observable/of';
const httpOptions = {
  headers: new HttpHeaders({
    'Content-Type': 'application/json'
  })
};

@Injectable()

export class ProductService {

  
  private _baseUrl: string;
  private _productListUrl: string = "api/Product/List";
  private _productInsertUrl: string = "api/Product/Insert";
  private _productEditUrl: string = "api/Product/Edit";
  private _productFindUrl: string = "api/Product/Find/";
  private _productDeleteUrl: string = "api/Product/Delete/";
  constructor(private _http: HttpClient, @Inject('BASE_URL') baseUrl: string) {
    this._baseUrl = baseUrl;
  }

  getProduct(id: number): Observable<Product> {
    return this._http.get<Product>(this._baseUrl + this._productFindUrl + id)
      .pipe(
        tap(product => this.log(`fetched product`)),
        catchError(this.handleError<Product>('getProduct'))
      );
  }

  getProducts(): Observable<Product[]> {
    return this._http.get<Product[]>(this._baseUrl + this._productListUrl)
      .pipe(
        tap(products => this.log(`fetched products`)),
        catchError(this.handleError('getProducts', []))
      );
  }

  insertProduct(product: Product): Observable<Product> {
    return this._http.post<Product>(this._baseUrl + this._productInsertUrl, product, httpOptions)
      .pipe(
        tap(products => this.log(`fetched products`)),
        catchError(this.handleError<Product>('insertProduct'))
      );
  }

  editProduct(product: Product): Observable<Product> {
    return this._http.post<Product>(this._baseUrl + this._productEditUrl, product, httpOptions)
      .pipe(
        tap(products => this.log(`fetched products`)),
        catchError(this.handleError<Product>('editProduct'))
      );
  }

  deleteProduct(product: Product): Observable<any> {
    return this._http.post<Product>(this._baseUrl + this._productDeleteUrl + product.id, product, httpOptions)
      .pipe(
        tap(products => this.log(`fetched products`)),
        catchError(this.handleError<Product>('deleteProduct'))
      );
  }

  private handleError<T>(operation = 'operation', result?: T) {
    return (error: any): Observable<T> => {

      console.log(error); // log to console instead      
      this.log(`${operation} failed: ${error.message}`);      
      return of(result as T);
    };
  }
   
  private log(message: string) {
    console.log("Product Service" + message);
  }
}

One of the things, I realized is that dotnet watch run sometimes will get stuck processing requests and it will feel like things have hanged. So I press Ctrl+C and dotnet watch will start processing things again. I have also hooked up Delete button with web api endpoint. Updated and working code is on Github Repo.

Next goal is to clean up default pages created by ASP.NET Core SPA template and host it on Azure website.

Wednesday, June 13, 2018

A4–Building App using Angular and ASP.NET Core 2.1 – Posting Form Values, Server-Side Validation, Displaying Error Messages

This post is a part of a series of posts that I am writing as I am building an app using Angular and ASP.NET Core 2.1. Links to previous posts –> A1, A2, A3, Github Repo

Today, my goal is hook up submit button for Insert, Edit and Delete Pages with HttpClient and post form values to ASP.NET Core Web API backend.

Below is code for product-insert.component.ts file, the code for product-edit.component.ts is same. Initially I am using HttpClient directly inside component.

import { Component, OnInit, Inject } from '@angular/core';
import { Product, IProduct } from '../product';
import { HttpClient, HttpHeaders } from '@angular/common/http';

const httpOptions = {
  headers: new HttpHeaders({
    'Content-Type': 'application/json',
    'Authorization': 'my-auth-token'
  })
};


@Component({
  selector: 'app-product-insert',
  templateUrl: './product-insert.component.html',
  styleUrls: ['./product-insert.component.css']
})

export class ProductInsertComponent implements OnInit {

  public product: IProduct;
  private _baseUrl: string;
  constructor(private _http: HttpClient, @Inject('BASE_URL') baseUrl: string) {
    this.product = new Product("", 0);
    this._baseUrl = baseUrl;
  }


  onProductSave(product: IProduct) {
    console.log(JSON.stringify(product));
    this._http.post<Product>(this._baseUrl + 'api/Product/Insert', product, httpOptions)
      .subscribe(result => {
        console.log(result);
      }, error => console.log(error));
    
  }
  ngOnInit() {

  }

}

I tested that when I clicked Save button, http post is getting called and same object being returned. In the image below, you can see that first json object is from component and other one is returned from API call.

image

I want to add some server side validation. Let’s say that price of product should be greater than 100. If price is less than 100 then throw BadRequest from server and display to user that error.

  [HttpPost("[action]")]
        public ActionResult<Product> Insert([FromBody] Product product)
        {
            _validateProduct(product);
            if (ModelState.IsValid)
            {
                //TODO: Save Product to database.
                return product;
            }
            return BadRequest(ModelState);
        }

        private void _validateProduct(Product product)
        {
            if (product.Price < 100)
            {
                ModelState.AddModelError(nameof(Product.Price), $"Product price cannot be less than 100, you entered {product.Price}");
            }
        }

In the code above, if the product price is less than 100, I am adding model error for key Price and message. This message we will have to show it to the user.

import { Component, OnInit, Inject } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { ActivatedRoute } from '@angular/router';
import { Product, IProduct } from '../product';

const httpOptions = {
  headers: new HttpHeaders({
    'Content-Type': 'application/json',
    'Authorization': 'my-auth-token'
  })
};


@Component({
  selector: 'app-product-edit',
  templateUrl: './product-edit.component.html',
  styleUrls: ['./product-edit.component.css']
})
export class ProductEditComponent implements OnInit {

  public errors: string[];
  public product: Product;
  id: number;
  private _baseUrl: string;
  constructor(private _http: HttpClient, private _activeRoute: ActivatedRoute, @Inject('BASE_URL') baseUrl: string) {
    this._baseUrl = baseUrl;
    this.id = this._activeRoute.snapshot.params['id'];
    this._http.get<Product>(baseUrl + 'api/Product/Find/' + this.id).subscribe(result => {
      this.product = result;
    }, error => console.log(error));


  }

  onProductSave(product: IProduct) {
    console.log(JSON.stringify(product));
    this._http.post<Product>(this._baseUrl + 'api/Product/Edit', product, httpOptions)
      .subscribe(result => {
        console.log(result);
      }, error => {
        console.log(error.error);
        if (error.status === 400) {
          let allErrors = error.error;
          console.log(allErrors);
          for (var fieldName in allErrors) {
            if (allErrors.hasOwnProperty(fieldName)) {
              this.errors.push(allErrors[fieldName]);
            }
          }
        }
      });
  }

  ngOnInit() {
    this.errors = [];
  }

}

I found this post by Carl and I am following his post to show error messages returned. Thank you Carl.

<br />
  <div class="alert alert-danger" role="alert" *ngIf="errors.length > 0">
    <ul>
      <li *ngFor="let error of errors">
        {{ error }}
      </li>
    </ul>
  </div>

This is displayed as shown in the image below.

image

I am displaying server side error message like below and marking the control as invalid as shown below.

import { Component, OnInit, Inject } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { ActivatedRoute } from '@angular/router';
import { Product, IProduct } from '../product';
import { FormControl, AbstractControl } from '@angular/forms';

const httpOptions = {
  headers: new HttpHeaders({
    'Content-Type': 'application/json',
    'Authorization': 'my-auth-token'
  })
};


@Component({
  selector: 'app-product-edit',
  templateUrl: './product-edit.component.html',
  styleUrls: ['./product-edit.component.css']
})
export class ProductEditComponent implements OnInit {

  public errors: string[];
  public product: Product;
  id: number;
  private _baseUrl: string;
  constructor(private _http: HttpClient, private _activeRoute: ActivatedRoute, @Inject('BASE_URL') baseUrl: string) {
    this._baseUrl = baseUrl;
    this.id = this._activeRoute.snapshot.params['id'];
    this._http.get<Product>(baseUrl + 'api/Product/Find/' + this.id).subscribe(result => {
      this.product = result;
    }, error => console.log(error));


  }

  onProductSave(productForm: any) {
    console.log((productForm));
    productForm.controls;
    let product = productForm.value;
    
    this._http.post<Product>(this._baseUrl + 'api/Product/Edit', product, httpOptions)
      .subscribe(result => {
        console.log(result);
      }, error => {
        console.log(error);
        console.log(error.error);
        if (error.status === 400) {
          let allErrors = error.error;
          for (var fieldName in allErrors) {
            if (allErrors.hasOwnProperty(fieldName)) {
              if (productForm.controls[fieldName]) {
                productForm.controls[fieldName].markAsTouched();
                productForm.controls[fieldName].setErrors({ invalid: true });
                this.errors.push(allErrors[fieldName]);
              } 
            }
          }
        }
      });
  }

  ngOnInit() {
    this.errors = [];
  }

}

This way the field is marked as invalid. I would like to show message below the field but it is taking longer for me to figure out today.

image

So that’s it folks for today, you can find the code on Github.

Next goal is to extract httpclient into a product service. And finish delete page.

Tuesday, June 12, 2018

A3–Building App using Angular and ASP.NET Core 2.1 – Form Validation

This post is a part of a series of posts that I am writing as I am building an app using Angular and ASP.NET Core 2.1. Links to previous posts –> A1, A2, Github Repo

Today, my goal was adding form validation to form controls. I added validation to Insert and Edit pages for Product. Validation on both the pages is very similar.

Add Product Validation

image

Same page but validation changes if you delete price and keep it null.

image

I learnt couple of things today regarding validation and forms.

1. There are many things to remember in hooking up things with form. For example, creating multiple validation is not that straight forward.

2. Out of the box there are couple of validators but real world scenarios almost always require you to have custom validation.

3. I wish there was an alternative to template variable. I do not like creating these variable on input fields. From an api standpoint it would have been nicer if everything was part of ngModel.

These are my naïve observations and stupid opinions based upon my limited knowledge regarding Angular internals.

Regarding my app, I am realizing that there is more code common between add and edit component. Perhaps I could utilize some shared component here. I am not too concerned with this right now. To get good grasp at validation, I am going to add more fields later.

Next goal is to be able to submit edit, insert, delete product using ASP.NET Web API as backend. Until then have a good night. And code is on GitHub.

Monday, June 11, 2018

A2–Building App using Angular and ASP.NET Core 2.1 – GitHub & Forms

This post is a part of a series of posts that I am writing as I am building an app using Angular and ASP.NET Core 2.1. The first post can be found here.

My first goal is to put this code on GitHub so people can follow progress and goof ups. Here is the link. The repo is called A100. Why A100 name? Because I couldn’t come up with a better name. There is no logic. Everything can be changed at any time in software so I just picked something and moved on.

You can clone it into a folder and if you have latest .NET Core SDK 2.1 installed you will be able to run the project as shown below.

PS M:\github\A100\src\A100> dotnet watch run

dotnet watch run is the best thing about building .NET web apps. You can make changes to file and see your website updated. No need to keep refreshing.

There is just one issue with dotnet watch when working with Angular and ASP.NET Core. And that is multiple urls. In the image below, there are three ports listening 5001 (https), 5000 and some random port generated by ng 55267.

image

You can use any url to test your application.

Next I am creating different pages edit, insert, details for viewing product information.

Details Page

image

Add New Page

image

Edit Product Page

image

Delete Confirmation Page

image

Product List Page

image

For all the methods, I am doing console.log as shown below.

image

One of the things that tripped me off was on initial page load when model was null. I had to add *ngIf=”product” at the root div. So that’s all I could accomplish today. The code is pushed to github.

Next I am going to tackle form validation.

Sunday, June 10, 2018

A1–Building App using Angular and ASP.NET Core 2.1

This post is a part of a series of posts that I will write as I build an app using Angular and ASP.NET Core 2.1. My goal with this series is not to show you how to do something but to build something little everyday and write about it. If I don’t build anything then I don’t write about it. I believe in concept of learn via building and learn via sharing. So let’s combine these two concepts. Please expect lots of mistakes being made by me and I hope you will correct them.

I have lot of experience building apps using AngularJS and ASP.NET MVC 5 but I wanted to learn Angular latest and ASP.NET Core 2.1. What I have done so far in this journey is listed below, so you have some background and you don’t assume that I am smart.

1. Watched Angular: Getting Started course on Pluralsight by Deborah Kurata

2. Finished Angular Tutorial: Tour of Heroes

3. Watching Angular: Forms course on Pluralsight by Mark Zamoyta

4. Built an app to showcase products and stuff.

My environment looks like this

1. Visual Studio 2017 15.7.3

2. Powershell

3. VS Code Latest

4. ASP.NET Core 2.1

5. Angular cli version listed below

image

6. Angular versions 5.2.0

I wanted to have server side back-end technology as ASP.NET Core and wanted to combine Angular with it. In latest ASP.NET Core 2.1, there is a template for getting started with this type of thing.

image

After application project was created, I was excited and I wanted to create a new Angular component. I executed this command on the command line ng generate component product-list and got the friend message to run npm install first. So I ran npm install and then did ng generate component product/product-list and used to get some errors. I don’t recall. However, after deleting contents of node_modules folder it started working.

Tip: Don’t run npm install. Just click Run or hit F5 and let visual studio install all dependencies.

In earlier version of ASP.NET Core 2.0 runtime, creating components using Angular CLI wasn’t that straight forward. In 2.1 working with Angular Cli has been fixed. I like this.

By default when you run the application, you get counter page and fetch data page. The fetch data page shows you how to retrieve data from ASP.NET WEB API endpoint.

I want to create product related pages such as insert, edit, delete, list, details and use ASP.NET WEB API. So first I created Product controller and related methods for doing insert, edit, delete, list and details. I used attribute routing. For simplicity, I am not connecting it to any database. I just want working methods. Then I tested these methods using PostMan client. Below is my Product Controller.

 [Route("api/[controller]")]
    public class ProductController : Controller
    {
        private static List<Product> Products = new List<Product>() {
            new Product { Id = 1, Title = "XYZ1", Price = 1,ImageUrl = "ImageUrl_XYZ1" },
            new Product { Id = 2, Title = "XYZ2", Price = 2,ImageUrl = "ImageUrl_XYZ2" },
            new Product { Id = 3, Title = "XYZ3", Price = 3,ImageUrl = "ImageUrl_XYZ3" },
            new Product { Id = 4, Title = "XYZ4", Price = 4,ImageUrl = "ImageUrl_XYZ4" },
            new Product { Id = 5, Title = "XYZ5", Price = 5,ImageUrl = "ImageUrl_XYZ5" },
            new Product { Id = 6, Title = "XYZ6", Price = 6,ImageUrl = "ImageUrl_XYZ6" },
            new Product { Id = 7, Title = "XYZ7", Price = 7,ImageUrl = "ImageUrl_XYZ7" },
            new Product { Id = 8, Title = "XYZ8", Price = 8,ImageUrl = "ImageUrl_XYZ8" },
            new Product { Id = 9, Title = "XYZ9", Price = 9,ImageUrl = "ImageUrl_XYZ9" }
            
        };
        [HttpGet("[action]")]
        public IEnumerable<Product> List()
        {
            return Products;
        }

        [HttpGet("[action]/{id:int}")]        
        public ActionResult<Product> Find(int id)
        {
            var product = Products.Where(x => x.Id == id).FirstOrDefault();
            if (product != null)
            {
                return product;
            }
            return NotFound($"Product with id {id} was not found");
        }

        [HttpPost("[action]")]
        public ActionResult<Product> Edit([FromBody] Product product)
        {
            return product;
        }

        [HttpPost("[action]/{id:int}")]
        public ActionResult<Product> Delete(int id)
        {
            return Ok("Delete Successfull");
        }

        [HttpPost("[action]")]
        public ActionResult<Product> Insert([FromBody] Product product)
        {
            return product;
        }
    }

Next up, I tried to create product-list angular component using angular cli using command ng g c product/product-list. I wanted to create product related component inside product folder. Hence, I used product/product-list as my component’s name. I am just going to borrow code from fetch-data component to retrieve product list.

import { Component, OnInit, Inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'app-product-list',
  templateUrl: './product-list.component.html',
  styleUrls: ['./product-list.component.css']
})
export class ProductListComponent implements OnInit {
  public products: Product[];
  constructor(http: HttpClient, @Inject('BASE_URL') baseUrl: string) {
    http.get<Product[]>(baseUrl + 'api/Product/List').subscribe(result => {
      this.products = result;
    }, error => console.log(error));
  }
  ngOnInit() {
  }
}
interface Product {
  id: number;
  title: string;
  price: number;
  imageUrl: string;
}

Next up, I hooked up navigation and you can see all the products being displayed. For brevity, I am not listing all the steps or code. I am going to put all this on GitHub so you can see the code and progress I make. Because, it turns out blogging every step is going to be time consuming. [edit- Github Repo here]

image

Creating angular components for delete, details, edit and insert as shown below.

image

image

Creating edit, delete, details, insert action buttons on product-list html page and adding routerLink so we can take appropriate actions. Below is how the page looks now.

Tip: Route should not have any ending /. Have product/insert instead of product/insert/

image

I hooked up these buttons with their respective components created in earlier step. Right now I have not created an markup for these individual action pages. That’s all I could get done today.

Next goal is to put this on GitHub and finish creating insert, edit, delete, details features of products page. See you next time. [edit- Github Repo here]

Friday, June 8, 2018

My Visual Studio 2019 Feature Wishlist

In this MSDN blog post, John Montgomery announced that the next version of Visual Studio is going to be 2019 and they have started planning for it. As I am very excited about this news, I couldn’t help myself from thinking about what features I would like to have in Visual Studio 2019. What could Microsoft add to VS that will make my job easier? So friends below is a list of features that are on my wish list.

1. Support for integrated terminal

Have you seen how snappy VS code is? It is light weight, fast and responsive. We need that kind of support for integrated terminal inside of Visual Studio 2019. The current option of right-clicking a node within Solution Explorer and clicking on open command prompt here is not ideal.

2. Auto Save

Alright, now you will say, “Mitul, you are saying copy all features from VS code and put in VS2019”. No. Not all the features but some things are really good in VS Code. I like auto save feature of VS Code and it just works. Can we have this in VS2019. Please…

3. Being able to easily add new files

When you hover in VS Code, you can see icons to add a new file, folder, refresh, and collapse all. This feature is very useful as it makes adding new files so much easier. I use Ctrl+F2 to invoke Add File Extension written by Mads Kristensen and this is one of my favorite extension but having this icon from VS code would be nice.

image

4. Command Window, Ctrl+Shift+P

In VS code when you hit Ctrl+Shift+P, you will see a command window appear and you can execute any command from there.

image

In VS, things are scattered around for doing these type of things such as,

1. Ctrl+Q

image

2. Ctrl+D

image

3. Command window

image

Can we have command execution workflow like VS code. You should be able to type command in english language instead of remember edit.somecommand.

5. Auto Download Next VS Update

We all appreciate the fast release cadence of VS but the yellow notification icon when it pops up every few days, it annoys me. When I see it, I want to update it. And this is good but I don’t like waiting for download. So can we have a setting where we can specify, “Always download new updates and prompt for update when done”. Download should happen in the background when new updates are available. I wish one day we can have silent VS updates in the background just like Chrome. I know this will be lot of work but may be some day in future. VS2019 may be..

6. Multi-cursor support

I have seen in some roadmap of VS2017 that multi-cursor support is coming. If it is not then we need multi-cursor support in VS2019.

7. Debugging - Support for Dump()

What is this Dump() method? If you have used LINQPad, then you will be familiar with Dump() method. In LINQPad you can put . after anything and call Dump() method and it will display the entire object in a nice format. It is so much easier to quickly hack up a script and get going. Let me show you something. In the image below, I called Dump() in many places to inspect different values and in the Results panel below you can see after each iteration those values were printed. “But Mitul how would this work in VS?”, you might ask. So let’s say if .Dump() was available then we can have it display these values in the output window. I imagine you could have an extension method in the Diagnostics assembly and display in output window.

image

8. Make animations and actions feel lightweight

Alright, this is highly subjective and you should remember that this is my wish list, so you might not feel the same way. What makes VS code light weight or feel light weight? When moving document to left or right it feels fast. There aren’t many animations in VS code whereas shifting documents within VS to left or right feels heavy. It would also be nice if there was keyboard support for docking documents within VS to left right or to next screen.

That’s all I have for now. We don’t want to list 10 features just to please OCD gods.

So what do you think about these features? Please leave a comment below and if I think of other feature ideas I will blog them again.

Enjoy day dreaming!

My Build 2018 Experience

I hate backpacks. Keep reading to find out why. I know its been a month since Build 2018 and I am late in writing this post but I didn’t wanted to feel guilty for not writing about my wonderful experience at Build 2018. So here you go.

I have attended 3 Build conferences one in 2013, 2016 and 2018. And I felt this was the best Build. After attending each Build, I felt that, that particular conference was the best conference. In this post, I want to reflect upon my experience attending Build 2018 conference. I traveled with family this year and so it wasn’t that lonely in Seattle. For my first conference, I was so excited to attend that I paid conference ticket using personal expense. After receiving Surface Pro tablet, I didn’t felt that bad. Past two conferences were all paid for by my company so it was awesome.

There are 386 Build 2018 videos. The content quality from Build is top notch. Every session is recorded and available online for later viewing and downloading. They have the ability to live stream sessions directly on Channel9 website. The work required to organize such a conference is beyond my imagination and I am always blown away by the scale of the conference. This brings me to one of the issues with Build this year. It was difficult to know where everything was. The build app was helpful in finding things and the app was much better than previous years. I later came to know that there were hands-on labs. Next time, I would recommend to spend few minutes just getting familiarized with conference layout so it becomes easier to find and locate a session.

Keynote

Keynote this year was about inspiring and selling us a vision about AI, Azure innovations, and intelligent Edge (ahem Windows). When you are standing in line with thousands of developers to watch keynote, you realize how big this conference is. The keynote hall was big and there were at least 8 insane size screens in the hall. So no matter where you got a seat you could not miss anything (unless you were on your phone). Over the past few conferences, I have noticed that more and more cool stuff is getting announced not in keynote but during the sessions. I feel there should be two mini keynotes detailing some common things that everyone should know.

Sessions

Sessions were action packed with high production quality content. Some of the sessions I attended and watched online are listed at the end of this post.  All the sessions are recorded and available on Ch9 and YouTube. I prefer YouTube and I want to thank ch9 team for putting it on YouTube. Due to YouTube Red, I downloaded sessions and was watching them while waiting at the airport and in flight. Another benefit of YouTube is that it will suggest you more Build 2018 videos. And because I forget to watch videos, after few days, I see a suggestion and I watch it.

Another pro tip for watching sessions

1. Download Build 2018 videos using PowerShell script

2. Use VLC media player to watch and quickly search videos. You will have to paste this link to the podcasts section and all the videos will appear on the right.

During the conference, when I was tired and didn’t felt like attending session, I was able to watch sessions on my phone that were live streamed while crashing on couch in the expo area.

Expo area

The expo area this year was huge. You are standing and walking most of the time and if you are carrying laptop in your backpack then it will wear you out. And I was tired like crazy. So that’s the reason why I hated carrying backpack. 

I was blown away by the presence of so many product/framework specific booth from Microsoft and of course from vendors and partners. I had the most fun interacting with Program Managers, Product Owners, and Engineers from Microsoft. Everyone greeted me very nicely. Some even approached me while I was just staring at the display TV or some chart saying, “Are you just going to stare at TV or ask me questions?”. Some went to great lengths—whiteboarding solutions, showing actual live demos and clearing my doubts. I learnt a lot by asking questions and talking to people. I could feel the openness, inclusiveness, curiosity in the culture. I did not wanted to leave Build because of this reason.

Since my last two Build, I have been spending more of my time in Expo area. This is the biggest benefit of attending a conference. Otherwise, you can watch keynote and sessions online. If you do not like talking to people then also attending in person has many benefits. For example, you can take picture with some legends—Scott Hanselman, Carl Franklin and Richard Campbell. In addition to that, this year we were able to pat dogs, horse and cats. I am not kidding there was an area with wooden fencing where you could pat dogs, horse and cats.

image

image

Booths visited

Windows admin center, PowerShell and Console Team, Eye Tracking, Adaptive Cards UI, TFS And VSTS, Branching and Release Management, Containers Team, Build Recap, Git branching insights, MSIX, MongoDB, .NET Platform, AI - ML.NET, Azure Functions, ASP.NET, Azure Essentials Training, AI School, Xamarin Essentials, IOT, Windows XAML, WinForms, Azure Resource Manager, Bot framework, ASP.NET Core, Launch Darkly

Food at Build

Alright, I know what you are expecting about food. It must be great, this and that. Food at conferences is mostly a miss and sometimes hit. During Build registration, there was an option for selecting Indian Vegetarian food. I was very excited after seeing this option. For the first two days, I couldn’t find Indian Vegetarian. It was there but it was located at a place that I came to know the last day. So its my fault for not discovering it and also it should have been placed in a more convenient location.

Closing thoughts

One of the things I was interested in was getting feedback from developers, program managers or anyone who has experience in software development about my career and my resume. And Build is the place where you have thousands of developers and leaders with years of experience in the field. I was literally carrying copies of my resume and asking few people about their opinion. Sometimes I felt shy and not confident in approaching people asking questions while they were busy with other folks. Well I developed courage and asked few individuals and got valuable piece of advice. I wish and humbly request Microsoft to dedicate a section where there would be mentors from software industry giving you advice regarding your career. Simple.

Everyone may not be able to attend this conference due to various reasons, I feel very lucky to have attended this three times. It was an honor and privilege to attend Build. I am thankful to University of Michigan for sending me.

List of Sessions attended or watched online.