MVC .NET notes

Submitted by matty on Thu, 03/22/2018 - 00:21

Here are some notes to help with coding MVC .Net.  Hopefully these will make sense and help remember certain basic syntax and library objects.  A great github repot .Net example can be found at www.github.com/mosh-hamedani.  Specifically the Vidly repository.

Links and packages:

Postman is a google chrome extension for doing http post testing.

// PM package for benchmarking
install-package glimpse.mvc5
install-package glimpse.ef6

Shortcuts:

  • ctrl-f5 : run without debugging
  • ctrl-shift-b : build
  • prop : template for member variable
  • ctorf : template for constructor function
  • ctrl+end+end : collapse code block
  • shift-esc : close file
  • ctrl+h : find and replace, ctrl+a for all
  • ctrl+k, ctrl+c : comment code block
  • ctrl + k, ctrl + u : uncomment code block

 

Gui Nuances:

Click on project name + F4 -> this focuses to Properties, then set SSL Enabled to True

 

Basics:

public ActionResult f() {}  // will return View() or ViewResult()
// Partial views are prefixed with _NameOfView by convention

//API often return http objects:
public IHttpActionResult GetMovies(string query = null) {}

int? i;   // nullable integer
Tests for null.  Integers by default are required:
!var.HasValue   // null test for int types
String.IsNullOrWhitespace(var)   // returns bool, tests for strings

String.Format("Mr {0} will be having {1}", name, drink)

//Getter example:
public string Title { get
                                      { if (True) return "Normal Title"
                                          else return "Alternate Title" }}

// Create constants in models for comparison in multiple locations: "Magic Numbers"
public static readonly byte Unknown = 0;
// then you can compare == ModelName.Unknown, instead of == 0

// Notice debug mode for compilation:
Web.config _> <system.web>   // within tag
<compilation debug="true" targetFramework="4.6.1" />
// release config Web.Release.config overrides this value.

typeof(string)  // returns the object type

Regex:

@"\d{4}"  <==> "\\d{4}"  //  '\' is an escape sequence.  '@' ignores this escape sequence

DB SQL:

Models -> IdentityModels.cs:ApplicationDbContext {
      public DbSet<TableName> TableName { get; set; }

Sql("INSERT INTO TableName VALUES (name, count) ('Populated Name', 50)");

using System.Data.Entity;

private ApplicationDbContext _context;

public ConstructorName()
{
    _context = new ApplicationDbContext();
}
protected override void Dispose(bool disposing)
{
    _context.Dispose();
}

var customers =

  • = _context.Customers;   // Links but lazy loads
  • = _context.Customers.ToList();   // Loads it all into memory
  • _context.Customers.SingleOrDefault(c => c.Id == id);
  • _context.Customers.Single(c => c.Id == id);   // May throw error if not found
  • _context.Customers.Include(c => c.MembershipType);   // Include another class
  • _context.Customers.Where(c => newCustomer.CustomerId.contains(c.Id);  // where Customers.CustomerId IN (c.Id)

_context.Customers.Add(customer)

TryUpdateModel(customerInDb);   // updates entire table, so not best for security, it's better to set the values either implicitly or by a mapper.

customerInDb.Name = customerName;
var movie = Mapper.Map<MovieDto, Movie>(movieDto)

_context.SaveChanges();  // Commit;

// Debugging idea:
try {
    _context.SaveChanges();
     }
catch (DbEntityValidationException e)
{ Console.WriteLine(e); }
// Debugger can inspect the value of e

 

Package Manager:

Init for new project:
enable-migration
update-database
add-migration InitialModel
enable-migration InitialModel -force        // force total rebuild.  It's better to add individual migrations:

add-migration NameofMigration
update-database

Within a migration SQL can be added

install-package automapper
// need to initialize in own App_Start -> MappingProfile.cs file, to CreateMap(s).  Also Global.asax must call initialize to add MappingProfile. Then Mapper.Map<dest, src> can be called in controllers.

Data Annotations:

using System.ComponentModel.DataAnnotations;

[Required(ErrorMessage = "Please enter customer's name")]

[StringLength(255)]

[Range(1,20)]

[ValidateAntiForgeryToken]

[HttpPost] [HttpPut] [HttpGet] [HttpDelete]

[Display (Name="Date of Birth")]

[Phone] [Url] [EmailAddress]

[Compare("Other Property")]

[RegularExpression("...")]

[CustomAnnotation]

// Implemented as a class:


public class Min18YearsIfAMember : ValidationAttribute
{    
     protected override ValidationResult IsValid(object value, ValidationContext validationContext)     
     {        
              if (False)
                  return new ValidationResult("Birthdate is required.");               
                 return (age >= 18? ValidationResult.Success                    : new ValidationResult("Customer should be at least 18 years old to subscribe monthly");     

} }

// No cache, all pathes, don't store.
[OutputCache(Duration=0, VaryByParam="*", NoStore=true)]
// 50 second cache on server:
[OutputCache(Duration=50, Location=OutputCacheLocation.Server)]
 

ASP .NET:

//Form example:
@using(Html.BeginForm("Action", "Model"))
{
       <div class="form-group">
           @Html.ValidationSummary(true, "Please fix the following errors")
           @Html.LabelFor(m => m.Name)
           @Html.ValidationMessageFor(m=>m.Name)
           @Html.TextBoxFor(m => m.Name, new {@class = "form-control"})
           @Html.CheckBoxFor(m => m.IsSubscribedToNewsletter)
           @Html.DropDownListFor(m => m.Customer.MembershipTypeId, new SelectList(Model.MembershipTypes, "Id", "Name"), "Select MembershipType", new {@class = "form-control"})
            @Html.TextBoxFor(m => m.Customer.BirthDate, "{0:d MMM yyyy}", new {@class="form-contrl"})
            @Html.HiddenFor(m => m.Customer.Id)
            @Html.AntiForgeryToken()
            button[type="submit].btn.btn-primary                    // zen coding!
}

@section scripts
{
    @Scripts.Render("~/bundles/jqueryval")
    <script>
          $(document).ready(function () {
           {
               // Javascript goes here

           });          
    </script>
}

 

Controllers:

// (ActionResult) return options
View()
ViewResult()
RedirectToAction("Action", "Controller")

// Filling a viewmodel:
var viewModel = new MovieFormViewModel(movie)      {  
    MovieGenres = _context.MovieGenres.ToList()           
 };
 return View("MovieForm", viewModel);

var dest = Mapper.map<destType, srcType>(src);

// An IHttpActionResult  method to return 201:
return Created(new Uri(Request.RequestUri + "/" + customer.Id), customerDto);
// Other IHttpActionResult return methods:
return Ok(Mapper.Map<aType,bType>(a);
return NotFound();

// Memory Cache:
if (MemoryCache.Default["Genres"] == null)
{
    MemoryCache.Default["Genres"] = _context.Genres.ToList();
}
var genres = MemoryCache.Default["Genres"] as IEnumberable<Genre>;

 

Authentication:

ASP:  @Html.AntiForgeryToken()
Controller:   [ValidateAntiForgeryToken]

// Disable session for optimization
Web.config -> <system.web> // within tag, case sensitive, Off
<sessionState mode="Off"></sessionState>

JS Stuff:

// in App_start _> WebApiConfig.cs insert at the top of the public void Register() function
var settings=config.Formatters.JsonFormatter.SerializerSettings;
settings.ContractResolver = new CamelCasePropertyNamesContractResolver();
settings.Formatting = Formatting.Indented;
// This makes get return camel case with first letter lowercase.
 

Autofac:

var builder = new ContainerBuilder();

builder.RegisterType<SMSLog>().As<ILog>().WithParameter(
           new ResolvedParameter(
                          (pi, ctx) => pi.ParameterType == typeof(string) && pi.Name == "phoneNumber"
                          (pi, ctx) => "+12345678"
           ));

// OR
// .WithParameter("phoneNumber", "+12345678"
// .WithParameter(new TypedParameter(typeof(string), "+12345678"));

var container = builder.Build();
var log = container.Resolve<ILog>();
log.Write("Test Message");

// OR random phone number
Random random = new Random();
builder.Register((c,p) => new SMSLog(p.Named<string>("phoneNumber"))).As<ILog>();
var container = builder.Build();
var log = container.Reslove<ILog>(new NamedParameter("phoneNumber", random.Next().ToString()));
log.Write("Testing");
 

// Another example where Child has no constructor and Parent has a ToString method:
var builder = new ContainerBuilder();
builder.RegisterType<Parent>();

// Property Injection (2 methods) to resolve the Parent class
//builder.RegisterType<Child>().PropertiesAutowired();
//builder.RegisterType<Child>().WithProperty("Parent", new Parent());

// Method Injection.  requires function Child.SetParent to be implemented above
builder.Register(c =>
{
    var child = new Child();
   child.SetParent(c.Resolve<Parent>());
   return child;
});

// OR an activating event handler:
//  builder.RegisterType<Child>()
//      .OnActivated((IActivatedEventsArgs<Child> e) =>
//       {
//           var p = e.Context.Resolve<Parent>();
//              e.Instance.SetParent(p);
//       });

var container = builder.Build();
var parent = container.Resolve<Child>().Parent;
Console.WriteLine(parent);

Tags