basquang™ on clouds

August 6, 2014

[Quartz.NET]: JobDataMap

Filed under: Quartz,Quartz.NET — basquang @ 2:33 PM
Tags: ,

What is JobDataMap?

The JobDataMap can be used to hold any number of (serializable) objects which you wish to have made available to the job instance when it executes. JobDataMap is an implementation of the IDictionary interface, and has some added convenience methods for storing and retrieving data of primitive types.

In my opinion, JobDataMap used to passing data between Quartz.NET host and Job instance?

Here is one sample code describes how to use JobDataMap.

  1. Create Console Application
  2. Install Quartz.NET from NuGet package
  3. Add logging configuration to App.config as below

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
    
      <configSections>
        <sectionGroup name="common">
          <section name="logging" type="Common.Logging.ConfigurationSectionHandler, Common.Logging"/>
        </sectionGroup>
      </configSections>
    
      <common>
        <logging>
          <factoryAdapter type="Common.Logging.Simple.ConsoleOutLoggerFactoryAdapter, Common.Logging">
            <arg key="showLogName" value="true"/>
            <arg key="showDataTime" value="true"/>
            <arg key="level" value="INFO"/>
            <arg key="dateTimeFormat" value="HH:mm:ss:fff"/>
          </factoryAdapter>
        </logging>
      </common>
      
        <startup> 
            <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
        </startup>
    </configuration>
    

  4. Define simple ColorJob as code below. This job simple reads data from JobDataMap and write to log

    [PersistJobDataAfterExecution]
    [DisallowConcurrentExecution]
    public class ColorJob : IJob
    {
    	private static readonly ILog log = LogManager.GetLogger(typeof(ColorJob));
    
    	// parameter names specific to this job
    	public const string FavoriteColor = "favorite color";
    	public const string ExecutionCount = "count";
    
    	// Since Quartz will re-instantiate a class every time it
    	// gets executed, members non-static member variables can
    	// not be used to maintain state!
    	private int counter = 1;
    
    	/// <summary>
    	/// Called by the <see cref="IScheduler" /> when a
    	/// <see cref="ITrigger" /> fires that is associated with
    	/// the <see cref="IJob" />.
    	/// </summary>
    	public virtual void Execute(IJobExecutionContext context)
    	{
    
    		// This job simply prints out its job name and the
    		// date and time that it is running
    		JobKey jobKey = context.JobDetail.Key;
    
    		// Grab and print passed parameters
    		JobDataMap data = context.JobDetail.JobDataMap;
    		string favoriteColor = data.GetString(FavoriteColor);
    		int count = data.GetInt(ExecutionCount);
    		log.InfoFormat(
    			"ColorJob: {0} executing at {1}\n  favorite color is {2}\n  execution count (from job map) is {3}\n  execution count (from job member variable) is {4}",
    			jobKey,
    			DateTime.Now.ToString("r"),
    			favoriteColor,
    			count, counter);
    
    		// increment the count and store it back into the 
    		// job map so that job state can be properly maintained
    		count++;
    		data.Put(ExecutionCount, count);
    
    		// Increment the local member variable 
    		// This serves no real purpose since job state can not 
    		// be maintained via member variables!
    		counter++;
    	}
    
    }
    

  5. Using the job in Program as code below:

    ILog log = LogManager.GetLogger(typeof(Program));
    
    // First we must get a reference to a scheduler
    ISchedulerFactory sf = new StdSchedulerFactory();
    IScheduler sched = sf.GetScheduler();
    
    // get a "nice round" time a few seconds in the future....
    DateTimeOffset startTime = DateBuilder.NextGivenSecondDate(null, 10);
    
    // job1 will only run 5 times (at start time, plus 4 repeats), every 10 seconds
    IJobDetail job1 = JobBuilder.Create<ColorJob>()
    	.WithIdentity("job1", "group1")
    	.Build();
    
    ISimpleTrigger trigger1 = (ISimpleTrigger)TriggerBuilder.Create()
    											   .WithIdentity("trigger1", "group1")
    											   .StartAt(startTime)
    											   .WithSimpleSchedule(x => x.WithIntervalInSeconds(10).WithRepeatCount(4))
    											   .Build();
    
    // pass initialization parameters into the job
    job1.JobDataMap.Put(ColorJob.FavoriteColor, "Green");
    job1.JobDataMap.Put(ColorJob.ExecutionCount, 1);
    
    // schedule the job to run
    DateTimeOffset scheduleTime1 = sched.ScheduleJob(job1, trigger1);
    log.Info(string.Format("{0} will run at: {1} and repeat: {2} times, every {3} seconds", 
    	job1.Key, 
    	scheduleTime1.ToString("r"), 
    	trigger1.RepeatCount, 
    	trigger1.RepeatInterval.TotalSeconds));           
    
    // All of the jobs have been added to the scheduler, but none of the jobs
    // will run until the scheduler has been started
    sched.Start();
    
    log.Info("------- Waiting 60 seconds... -------------");
    try
    {
    	// wait five minutes to show jobs
    	Thread.Sleep(300 * 1000);
    	// executing...
    }
    catch (ThreadInterruptedException)
    {
    }
    
    sched.Shutdown(true);          
    

  6. The output similar like this

    14:29:20:014 [INFO]  Quartz.Impl.StdSchedulerFactory - Default Quartz.NET proper
    ties loaded from embedded resource file
    14:29:20:112 [INFO]  Quartz.Impl.StdSchedulerFactory - Using default implementat
    ion for object serializer
    14:29:20:174 [INFO]  Quartz.Impl.StdSchedulerFactory - Using default implementat
    ion for ThreadExecutor
    14:29:20:202 [INFO]  Quartz.Core.SchedulerSignalerImpl - Initialized Scheduler S
    ignaller of type: Quartz.Core.SchedulerSignalerImpl
    14:29:20:203 [INFO]  Quartz.Core.QuartzScheduler - Quartz Scheduler v.2.2.4.400
    created.
    14:29:20:206 [INFO]  Quartz.Simpl.RAMJobStore - RAMJobStore initialized.
    14:29:20:212 [INFO]  Quartz.Core.QuartzScheduler - Scheduler meta-data: Quartz S
    cheduler (v2.2.4.400) 'DefaultQuartzScheduler' with instanceId 'NON_CLUSTERED'
      Scheduler class: 'Quartz.Core.QuartzScheduler' - running locally.
      NOT STARTED.
      Currently in standby mode.
      Number of jobs executed: 0
      Using thread pool 'Quartz.Simpl.SimpleThreadPool' - with 10 threads.
      Using job-store 'Quartz.Simpl.RAMJobStore' - which does not support persistenc
    e. and is not clustered.
    
    14:29:20:213 [INFO]  Quartz.Impl.StdSchedulerFactory - Quartz scheduler 'Default
    QuartzScheduler' initialized
    14:29:20:213 [INFO]  Quartz.Impl.StdSchedulerFactory - Quartz scheduler version:
     2.2.4.400
    14:29:20:260 [INFO]  Lesson4.Program - group1.job1 will run at: Wed, 06 Aug 2014
     07:29:30 GMT and repeat: 4 times, every 10 seconds
    14:29:20:264 [INFO]  Quartz.Core.QuartzScheduler - Scheduler DefaultQuartzSchedu
    ler_$_NON_CLUSTERED started.
    14:29:20:266 [INFO]  Lesson4.Program - ------- Waiting 60 seconds... -----------
    --
    14:29:30:111 [INFO]  Lesson4.ColorJob - ColorJob: group1.job1 executing at Wed,
    06 Aug 2014 14:29:30 GMT
      favorite color is Green
      execution count (from job map) is 1
      execution count (from job member variable) is 1
    14:29:39:999 [INFO]  Lesson4.ColorJob - ColorJob: group1.job1 executing at Wed,
    06 Aug 2014 14:29:39 GMT
      favorite color is Green
      execution count (from job map) is 2
      execution count (from job member variable) is 1
    14:29:49:999 [INFO]  Lesson4.ColorJob - ColorJob: group1.job1 executing at Wed,
    06 Aug 2014 14:29:49 GMT
      favorite color is Green
      execution count (from job map) is 3
      execution count (from job member variable) is 1
    14:29:59:999 [INFO]  Lesson4.ColorJob - ColorJob: group1.job1 executing at Wed,
    06 Aug 2014 14:29:59 GMT
      favorite color is Green
      execution count (from job map) is 4
      execution count (from job member variable) is 1
    14:30:09:999 [INFO]  Lesson4.ColorJob - ColorJob: group1.job1 executing at Wed,
    06 Aug 2014 14:30:09 GMT
      favorite color is Green
      execution count (from job map) is 5
      execution count (from job member variable) is 1
    14:34:20:252 [INFO]  Quartz.Core.QuartzScheduler - Scheduler DefaultQuartzSchedu
    ler_$_NON_CLUSTERED shutting down.
    14:34:20:257 [INFO]  Quartz.Core.QuartzScheduler - Scheduler DefaultQuartzSchedu
    ler_$_NON_CLUSTERED paused.
    14:34:20:653 [INFO]  Quartz.Core.QuartzScheduler - Scheduler DefaultQuartzSchedu
    ler_$_NON_CLUSTERED Shutdown complete.
    Press any key to continue . . .
    

Hope this help!

August 4, 2014

[Quartz.NET]: Configure NLog for logging

Filed under: Logging,Quartz,Quartz.NET — basquang @ 5:47 PM
Tags: ,

In previous article Configure Logging I described how to configure Logging in configuration file using Common.Logging.Simple.ConsoleOutLoggerFactoryAdapter.

In this article, I will describe how to configure NLog in Quartz application.

Because Quartz.NET using Common.Logging frameworks, so there are two implementations dependency when you want to use NLogLoggerFactoryAdapter:

  • Common.Logging.NLog20 is linked against NLog 2.0.0.2
  • Common.Logging.NLog10 is linked against NLog 1.0.0.505

So you need to install correct version of Common.Logging.NLog and NLog.

  1. Create Console Application
  2. Install Quartz.NET from NutGet. By default at this time NuGet will install following packages. By default Quartz use Common.Logging v2.1.2

    <packages>
      <package id="Common.Logging" version="2.1.2" targetFramework="net45" />
      <package id="Quartz" version="2.2.4" targetFramework="net45" />
    </packages>
    

  3. Add the configuration code below to configure NLog in the App.config file

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
    
      <configSections>
        <sectionGroup name="common">
          <section name="logging" type="Common.Logging.ConfigurationSectionHandler, Common.Logging" />
        </sectionGroup>
        <section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog" />
      </configSections>
    
      <common>
        <logging>
          <factoryAdapter type="Common.Logging.NLog.NLogLoggerFactoryAdapter, Common.Logging.NLog20">
            <arg key="configType" value="INLINE" />
          </factoryAdapter>
        </logging>
      </common>
    
      <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <targets>
          <target name="file" xsi:type="File" layout="${date:format=HH\:MM\:ss} ${logger} ${message}" fileName="${basedir}/logs/logfile.txt" />
        </targets>
        <rules>
          <logger name="*" minlevel="Debug" writeTo="file" />
        </rules>
      </nlog>
    
      <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
      </startup>       
    </configuration>
    

  4. Create simple Job like this

    public class SimpleJob : IJob
        {
            private static ILog logging = LogManager.GetLogger(typeof(SimpleJob));
    
            public void Execute(IJobExecutionContext context)
            {
                logging.InfoFormat("Hello from job");
            }
        }
    

  5. Using the job in Program

    ILog log = LogManager.GetLogger(typeof(Program));
    
    // First we must get a reference to a scheduler
    ISchedulerFactory sf = new StdSchedulerFactory();
    IScheduler sched = sf.GetScheduler();
    
    //////////////////
    try
    {
    	var startTime = DateTimeOffset.Now.AddSeconds(5);
    
    	var job = JobBuilder.Create<SimpleJob>()
    						.WithIdentity("job1", "group1")
    						.Build();
    
    	var trigger = TriggerBuilder.Create()
    		.WithIdentity("trigger1", "group1")
    		.StartAt(startTime)
    		.WithSimpleSchedule(x => x.WithIntervalInSeconds(10).WithRepeatCount(4))
    		.Build();
    
    	sched.ScheduleJob(job, trigger);       
    
    	sched.Start();
    	Thread.Sleep(TimeSpan.FromSeconds(30));
    }
    finally
    {
    	sched.Shutdown(true);
    }
    

  6. When press F5 to run the application following error will appear

    Unable to create type ‘Common.Logging.NLog.NLogLoggerFactoryAdapter, Common.Logging.NLog20’

  7. To resolve this issue. Install Common.Logging.NLog20 from NuGet by running following command in order.NOTE: To use NLong we need to update Common.Logging to version 2.2.0

    Install-Package Common.Logging.NLog20

    Install-Package Common.Logging.Core

    Install-Package Common.Logging -Version 2.2.0

    This command will install following packages

    <packages>
      <package id="Common.Logging" version="2.2.0" targetFramework="net45" />
      <package id="Common.Logging.Core" version="2.2.0" targetFramework="net45" />
      <package id="Common.Logging.NLog20" version="2.2.0" targetFramework="net45" />
      <package id="NLog" version="2.0.0.2000" targetFramework="net45" />
      <package id="Quartz" version="2.2.4" targetFramework="net45" />
    </packages>
    

  8. Now run application again and see the output of logged file in the path bin\debug\logs\logfile.txt

The logged file created by NLog in the configuration you have defined above.

Hope this help!

 

[Quartz.NET]: Configure Logging

Filed under: Logging,Quartz,Quartz.NET — basquang @ 5:02 PM
Tags: ,

Common.Logging can be configured to use different logging frameworks under the hood; namely Enterprise Library, Log4Net and NLog.

However, to keep things simple in last post Get Started we take the simple route and configure logging using code to just log to the console using Common.Logging basic logging mechanism.

Common.Logging.LogManager.Adapter = new Common.Logging.Simple.ConsoleOutLoggerFactoryAdapter { Level = Common.Logging.LogLevel.Info};

This blog post describe how to configure Logging in application configuration file.

  1. Create Console Application
  2. Install Quartz.NET from NuGet
  3. Add following code in the App.config to configure Logging for Quart. In this logging configuration we use ConsoleOutLoggerFactoryAdapter to display log to the Console.Out screen.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  
  <configSections>   
    <sectionGroup name="common">
      <section name="logging" type="Common.Logging.ConfigurationSectionHandler, Common.Logging"/>
    </sectionGroup>
  </configSections>

  <common>
    <logging>
      <factoryAdapter type="Common.Logging.Simple.ConsoleOutLoggerFactoryAdapter, Common.Logging">
        <arg key="showLogName" value="true"/>
        <arg key="showDataTime" value="true"/>
        <arg key="level" value="INFO"/>
        <arg key="dateTimeFormat" value="HH:mm:ss:fff"/>
      </factoryAdapter>
    </logging>
  </common>
  
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
</configuration>

  1. Add a simple Job like this. In this Job we use log the execution of the Job by writing the message “Hello World…”

    public class HelloJob : IJob
        {
            //Get logging configuration
            private static ILog _log = LogManager.GetLogger(typeof(HelloJob));
    
            /// <summary> 
            /// Called by the <see cref="IScheduler" /> when a
            /// <see cref="ITrigger" /> fires that is associated with
            /// the <see cref="IJob" />.
            /// </summary>
            public virtual void Execute(IJobExecutionContext context)
            {
    
                // Say Hello to the World and display the date/time
                _log.Info(string.Format("Hello World! - {0}", System.DateTime.Now.ToString()));
            }
    
        }
    

  2. Using the Job in Program class as below
  3. //Get Logging configuration
    ILog log = LogManager.GetLogger(typeof(Program));
    
    // First we must get a reference to a scheduler
    ISchedulerFactory sf = new StdSchedulerFactory();
    IScheduler sched = sf.GetScheduler();
    
    log.Info("------- Scheduling Job  -------------------");
    
    // define the job and tie it to our HelloJob class
    IJobDetail job = JobBuilder.Create<HelloJob>()
    	.WithIdentity("job1", "group1")
    	.Build();
    
    // Trigger the job to run on the next round minute
    ITrigger trigger = TriggerBuilder.Create()
    	.WithIdentity("trigger1", "group1")
    	.StartNow()
    	.WithSimpleSchedule(x => x
    	.WithIntervalInSeconds(10)
    	.RepeatForever())
    	.Build();
    
    // Tell quartz to schedule the job using our trigger
    sched.ScheduleJob(job, trigger);           
    
    // Start up the scheduler (nothing can actually run until the 
    // scheduler has been started)
    sched.Start();
    
    // wait long enough so that the scheduler as an opportunity to 
    // run the job!
    
    // wait 65 seconds to show jobs
    Thread.Sleep(TimeSpan.FromSeconds(60));
    
    // shut down the scheduler
    sched.Shutdown(true);
    

  4. The Console screen output will display the message (execute the job) you have been defined each 10 seconds 6 time (within 60 seconds)

Hope this help

[Quartz.NET]: Get Started

Filed under: Quartz,Quartz.NET — basquang @ 4:32 PM
Tags: ,

What is Quartz.NET?

“Quartz.NET is a full-featured, open source job scheduling system that can be used from smallest apps to large scale enterprise systems. ”

Quartz.NET is a pure .NET library written in C# and is a port of very popular open source Java job scheduling framework, Quartz. This project owes very much to original Java project, it’s father James House and the project contributors.

http://www.quartz-scheduler.net/

How to get started?

The official guide here: http://www.quartz-scheduler.net/documentation/quartz-2.x/quick-start.html

And the steps here:

  1. Create Console Application
  2. Install Quartz.NET from NuGet package by running following command

    Install-Package Quartz

    Quartz NuGet will install following packages at this time I writing the blog post

    <packages>
      <package id="Common.Logging" version="2.1.2" targetFramework="net45" />
      <package id="Quartz" version="2.2.4" targetFramework="net45" />
    </packages>
    
  3. Add following code in the namespace
  4. Program class

    class Program
        {
            static void Main(string[] args)
            {
                try
                {
                    //Configure simple logging
                    Common.Logging.LogManager.Adapter = new Common.Logging.Simple.ConsoleOutLoggerFactoryAdapter { Level = Common.Logging.LogLevel.Info };
    
                    // Grab the Scheduler instance from the Factory 
                    IScheduler scheduler = StdSchedulerFactory.GetDefaultScheduler();
    
                    // and start it off
                    scheduler.Start();
    
                    // define the job and tie it to our HelloJob class
                    IJobDetail job = JobBuilder.Create<HelloJob>()
                        .WithIdentity("job1", "group1")
                        .Build();
    
                    // Trigger the job to run now, and then repeat every 10 seconds
                    ITrigger trigger = TriggerBuilder.Create()
                        .WithIdentity("trigger1", "group1")
                        .StartNow()
                        .WithSimpleSchedule(x => x
                            .WithIntervalInSeconds(10)
                            .RepeatForever())
                        .Build();
    
                    // Tell quartz to schedule the job using our trigger
                    scheduler.ScheduleJob(job, trigger);
    
    
                    // some sleep to show what's happening
                    Thread.Sleep(TimeSpan.FromSeconds(60));
    
                    // and last shut down the scheduler when you are ready to close your program
                    scheduler.Shutdown();
                }
                catch (SchedulerException se)
                {
                    Console.WriteLine(se);
                }
    
    
                Console.WriteLine("Press any key to close the application");
                Console.ReadKey();
    
            }
        }
    

    Job class

    public class HelloJob : IJob
        {
            public void Execute(IJobExecutionContext context)
            {
                Console.WriteLine("Greetings from HelloJob!");
            }
        }
    
  5. The output like this.

Hope this help!

July 11, 2014

[MVC]: Migrate an existing project using ASP.NET Identity 1.0 to 2.0 Complete

Filed under: Entity Framework (EF),MVC — basquang @ 4:13 PM
Tags: ,

Scenario:

You have an existing ASP.NET MVC project that using previous version of ASP.NET Identity (v1.0.0). You want to use new features which announced in ASP.NET Identity 2.0 RTM versions:

  • Two-Factor Authentication
  • Account Lockout
  • Account Confirmation
  • Password Reset
  • Security Stamp (Sign out everywhere)
  • Make the type of Primary Key be extensible for Users and Roles
  • Support IQueryable on Users and Roles
  • Delete User account
  • IdentityFactory Middleware/ CreatePerOwinContext
  • Indexing on Username
  • Enhanced Password Validator

For the full announcement please visit the official link here Announcing RTM of ASP.NET Identity 2.0.0

Solution:

As mentioned in the release, you need to migrate existing project using ASP.NET Identity 1.0 to 2.0 version. There are some guide here you can follow:

Updating ASP.NET applications from ASP.NET Identity 1.0 to 2.0.0-alpha1

Upgrading an Existing Project from ASP.NET Identity 1.0 to 2.0

But these guides is not completely, just steps to migrate ASP.NET Identity Code First database from v1.0 to v2.0.

So this article will describe complete steps to migrate your existing MVC project using ASP.NET Identity 1.0 to 2.0 RTM which include “Password Reset” function.

Existing project

My current MVC project using ASP.NET Identity 1.0 as noted in packages.config here:

<package id="Microsoft.AspNet.Identity.Core" version="1.0.0" targetFramework="net45" />
<package id="Microsoft.AspNet.Identity.EntityFramework" version="1.0.0" targetFramework="net45" />
<package id="Microsoft.AspNet.Identity.Owin" version="1.0.0" targetFramework="net45" />

The AspNetUsers table in ASP.NET Identity 1.0 has 5 columns: Id, UserName, PasswordHash, SecurityStamp and Discriminator:

Migrating ASP.NET Identity Database from 1.0 to 2.0

Step 1: Update ASP.NET Identity Packages

Open Package Manager Console then run following command in order

PM> Update-Package Microsoft.AspNet.Identity.Core

PM> Update-Package Microsoft.AspNet.Identity.EntityFramework

Restart Visual Studio then run this command in Package Manager Console

PM> Update-Package Microsoft.AspNet.Identity.Owin

Now run the application an try to logging on old user, you will see the error:

Server Error in ‘/’ Application.


The model backing the ‘ApplicationDbContext’ context has changed since the database was created. This could have happened because the model used by ASP.NET Identity Framework has changed or the model being used in your application has changed. To resolve this issue, you need to update your database. Consider using Code First Migrations to update the database (http://go.microsoft.com/fwlink/?LinkId=301867).  Before you update your database using Code First Migrations, please disable the schema consistency check for ASP.NET Identity by setting throwIfV1Schema = false in the constructor of your ApplicationDbContext in your application.
       public ApplicationDbContext() : base(“ApplicationServices”, throwIfV1Schema:false)

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. 

Exception Details: System.InvalidOperationException: The model backing the ‘ApplicationDbContext’ context has changed since the database was created. This could have happened because the model used by ASP.NET Identity Framework has changed or the model being used in your application has changed. To resolve this issue, you need to update your database. Consider using Code First Migrations to update the database (http://go.microsoft.com/fwlink/?LinkId=301867).  Before you update your database using Code First Migrations, please disable the schema consistency check for ASP.NET Identity by setting throwIfV1Schema = false in the constructor of your ApplicationDbContext in your application.
       public ApplicationDbContext() : base(“ApplicationServices”, throwIfV1Schema:false)

Source Error: 

 

Line 10:     public class ApplicationDbContext : IdentityDbContext<ApplicationUser>

Line 11:     {

Line 12:         public ApplicationDbContext()

Line 13:             : base("DefaultConnection")

Line 14:         {


Source File: c:\Users\Administrator\Documents\Visual Studio 2013\Projects\MvcIdentity2Migration\MvcIdentity2Migration\Models\IdentityModels.cs    Line: 12 

 

To resolve this error, we need to migrate existing code first database to 2.0 version

Step 2: Migrate Code First database.

Open IdentityModels.cs class file then change to the ApplicationDbContext constructor as below:

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
    {
        public ApplicationDbContext()
            : base("DefaultConnection", throwIfV1Schema: false)
        {
        }
        public static ApplicationDbContext Create()
        {
            return new ApplicationDbContext();
        }
    }

Open Package Manager Console then run these command

PM> Enable-Migrations

PM> Add-Migration Update1

Here Update1 is an identifier you can have for this migration. The migrations code generated should as below

public partial class Update1 : DbMigration
    {
        public override void Up()
        {
            RenameColumn(table: "dbo.AspNetUserClaims", name: "User_Id", newName: "UserId");
            RenameIndex(table: "dbo.AspNetUserClaims", name: "IX_User_Id", newName: "IX_UserId");
            DropPrimaryKey("dbo.AspNetUserLogins");
            AddColumn("dbo.AspNetUsers", "Email", c => c.String(maxLength: 256));
            AddColumn("dbo.AspNetUsers", "EmailConfirmed", c => c.Boolean(nullable: false));
            AddColumn("dbo.AspNetUsers", "PhoneNumber", c => c.String());
            AddColumn("dbo.AspNetUsers", "PhoneNumberConfirmed", c => c.Boolean(nullable: false));
            AddColumn("dbo.AspNetUsers", "TwoFactorEnabled", c => c.Boolean(nullable: false));
            AddColumn("dbo.AspNetUsers", "LockoutEndDateUtc", c => c.DateTime());
            AddColumn("dbo.AspNetUsers", "LockoutEnabled", c => c.Boolean(nullable: false));
            AddColumn("dbo.AspNetUsers", "AccessFailedCount", c => c.Int(nullable: false));
            AlterColumn("dbo.AspNetRoles", "Name", c => c.String(nullable: false, maxLength: 256));
            AlterColumn("dbo.AspNetUsers", "UserName", c => c.String(nullable: false, maxLength: 256));
            AddPrimaryKey("dbo.AspNetUserLogins", new[] { "LoginProvider", "ProviderKey", "UserId" });
            CreateIndex("dbo.AspNetRoles", "Name", unique: true, name: "RoleNameIndex");
            CreateIndex("dbo.AspNetUsers", "UserName", unique: true, name: "UserNameIndex");
            DropColumn("dbo.AspNetUsers", "Discriminator");
        }
        
        public override void Down()
        {
            AddColumn("dbo.AspNetUsers", "Discriminator", c => c.String(nullable: false, maxLength: 128));
            DropIndex("dbo.AspNetUsers", "UserNameIndex");
            DropIndex("dbo.AspNetRoles", "RoleNameIndex");
            DropPrimaryKey("dbo.AspNetUserLogins");
            AlterColumn("dbo.AspNetUsers", "UserName", c => c.String());
            AlterColumn("dbo.AspNetRoles", "Name", c => c.String(nullable: false));
            DropColumn("dbo.AspNetUsers", "AccessFailedCount");
            DropColumn("dbo.AspNetUsers", "LockoutEnabled");
            DropColumn("dbo.AspNetUsers", "LockoutEndDateUtc");
            DropColumn("dbo.AspNetUsers", "TwoFactorEnabled");
            DropColumn("dbo.AspNetUsers", "PhoneNumberConfirmed");
            DropColumn("dbo.AspNetUsers", "PhoneNumber");
            DropColumn("dbo.AspNetUsers", "EmailConfirmed");
            DropColumn("dbo.AspNetUsers", "Email");
            AddPrimaryKey("dbo.AspNetUserLogins", new[] { "UserId", "LoginProvider", "ProviderKey" });
            RenameIndex(table: "dbo.AspNetUserClaims", name: "IX_UserId", newName: "IX_User_Id");
            RenameColumn(table: "dbo.AspNetUserClaims", name: "UserId", newName: "User_Id");
        }
    }

Next we need to persist it to the database. Run the command ‘Update-Database –verbose’. The verbose flag lets you view the SQL queries generated. This should pass as expected.

The AspNetUsers in ASP.NET Identity 2.0 is as image below

Now run application and try to logon with old user. It will logged on as expected.

Adding “Password Reset” function to existing project.

Step 1: Right click on App_Start folder then add new IdentityConfig.cs with code bellow

public class ApplicationUserManager : UserManager<ApplicationUser>
    {
        public ApplicationUserManager(IUserStore<ApplicationUser> store)
            : base(store)
        {
        }

        public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
        {
            var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>()));
            // Configure validation logic for usernames
            manager.UserValidator = new UserValidator<ApplicationUser>(manager)
            {
                AllowOnlyAlphanumericUserNames = false,
                RequireUniqueEmail = true
            };
            // Configure validation logic for passwords
            manager.PasswordValidator = new PasswordValidator
            {
                RequiredLength = 6,
                RequireNonLetterOrDigit = true,
                RequireDigit = true,
                RequireLowercase = true,
                RequireUppercase = true,
            };
            // Register two factor authentication providers. This application uses Phone and Emails as a step of receiving a code for verifying the user
            // You can write your own provider and plug in here.
            manager.RegisterTwoFactorProvider("PhoneCode", new PhoneNumberTokenProvider<ApplicationUser>
            {
                MessageFormat = "Your security code is: {0}"
            });
            manager.RegisterTwoFactorProvider("EmailCode", new EmailTokenProvider<ApplicationUser>
            {
                Subject = "Security Code",
                BodyFormat = "Your security code is: {0}"
            });
            manager.EmailService = new EmailService();
            manager.SmsService = new SmsService();
            var dataProtectionProvider = options.DataProtectionProvider;
            if (dataProtectionProvider != null)
            {
                manager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(dataProtectionProvider.Create("ASP.NET Identity"));
            }
            return manager;
        }
    }

    public class EmailService : IIdentityMessageService
    {
        public Task SendAsync(IdentityMessage message)
        {
            // Plug in your email service here to send an email.
            MailMessage email = new MailMessage("xxx@hotmail.com", message.Destination);
            email.Subject = message.Subject;
            email.Body = message.Body;
            email.IsBodyHtml = true;
            var mailClient = new SmtpClient("smtp.live.com", 587) { Credentials = new NetworkCredential("xxx@hotmail.com", "password"), EnableSsl = true };
            return mailClient.SendMailAsync(email);
        }
    }

    public class SmsService : IIdentityMessageService
    {
        public Task SendAsync(IdentityMessage message)
        {
            // Plug in your sms service here to send a text message.
            return Task.FromResult(0);
        }
    }

Step 2: Open the IdentityModels.cs class file then change code as below:

public class ApplicationUser : IdentityUser
    {
        public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
        {
            // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
            var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
            // Add custom user claims here
            return userIdentity;
        }
    }

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
    {
        public ApplicationDbContext()
            : base("DefaultConnection", throwIfV1Schema:false)
        {
        }

        public static ApplicationDbContext Create()
        {
            return new ApplicationDbContext();
        }
    }

Step 3: Open the Startup.Auth.cs class file then add these following code in the start of ConfigureAuth method

public void ConfigureAuth(IAppBuilder app)
	{
		// Configure the db context and user manager to use a single instance per request
		app.CreatePerOwinContext(ApplicationDbContext.Create);
		app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);

		// Enable the application to use a cookie to store information for the signed in user
		app.UseCookieAuthentication(new CookieAuthenticationOptions
		{
			AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
			LoginPath = new PathString("/Account/Login"),
			Provider = new CookieAuthenticationProvider
			{
				OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
					validateInterval: TimeSpan.FromMinutes(30),
					regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
			}
		});
		// Use a cookie to temporarily store information about a user logging in with a third party login provider
		app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

		// Uncomment the following lines to enable logging in with third party login providers
		//app.UseMicrosoftAccountAuthentication(
		//    clientId: "",
		//    clientSecret: "");

		//app.UseTwitterAuthentication(
		//   consumerKey: "",
		//   consumerSecret: "");

		//app.UseFacebookAuthentication(
		//   appId: "",
		//   appSecret: "");

		//app.UseGoogleAuthentication();
	} 

Step 4: Change AccountViewModels.cs class file. Open the file then add to view model for the Reset Password function

public class ResetPasswordViewModel
    {
        [Required]
        [EmailAddress]
        [Display(Name = "Email")]
        public string Email { get; set; }

        [Required]
        [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
        [DataType(DataType.Password)]
        [Display(Name = "Password")]
        public string Password { get; set; }

        [DataType(DataType.Password)]
        [Display(Name = "Confirm password")]
        [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
        public string ConfirmPassword { get; set; }

        public string Code { get; set; }
    }

    public class ForgotPasswordViewModel
    {
        [Required]
        [EmailAddress]
        [Display(Name = "Email")]
        public string Email { get; set; }
    }

Step 5: Change the AccountController.cs class file

Modify AccountController constructor method as bellow

private ApplicationUserManager _userManager;

public AccountController()
{
}

public AccountController(ApplicationUserManager userManager)
{
	UserManager = userManager;
}

public ApplicationUserManager UserManager
{
	get
	{
		return _userManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
	}
	private set
	{
		_userManager = value;
	}
}

Remember to add this line of code in using code

using Microsoft.AspNet.Identity.Owin;

Step 6: Add Forgot Password Actions

// GET: /Account/ForgotPassword
[AllowAnonymous]
public ActionResult ForgotPassword()
{
	return View();
}

//
// POST: /Account/ForgotPassword
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> ForgotPassword(ForgotPasswordViewModel model)
{
	if (ModelState.IsValid)
	{
		var user = await UserManager.FindByEmailAsync(model.Email);
		if (user == null || !(await UserManager.IsEmailConfirmedAsync(user.Id)))
		{
			ModelState.AddModelError("", "The user either does not exist or is not confirmed.");
			return View();
		}

		// For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=320771
		// Send an email with this link
		var code = await UserManager.GeneratePasswordResetTokenAsync(user.Id);
		var callbackUrl = Url.Action("ResetPassword", "Account",
		new { UserId = user.Id, code = code }, protocol: Request.Url.Scheme);
		await UserManager.SendEmailAsync(user.Id, "Reset Password",
		"Please reset your password by clicking here: <a href=\"" + callbackUrl + "\">link</a>");     

		return RedirectToAction("ForgotPasswordConfirmation", "Account");
	}

	// If we got this far, something failed, redisplay form
	return View(model);
}

//
// GET: /Account/ForgotPasswordConfirmation
[AllowAnonymous]
public ActionResult ForgotPasswordConfirmation()
{
	return View();
}

Step 7: Add Reset Password Actions

// GET: /Account/ResetPassword
[AllowAnonymous]
public ActionResult ResetPassword(string code)
{
	if (code == null)
	{
		return View("Error");
	}
	return View();
}

//
// POST: /Account/ResetPassword
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> ResetPassword(ResetPasswordViewModel model)
{
	if (ModelState.IsValid)
	{
		var user = await UserManager.FindByEmailAsync(model.Email);
		if (user == null)
		{
			ModelState.AddModelError("", "No user found.");
			return View();
		}
		IdentityResult result = await UserManager.ResetPasswordAsync(user.Id, model.Code, model.Password);
		if (result.Succeeded)
		{
			return RedirectToAction("ResetPasswordConfirmation", "Account");
		}
		else
		{
			AddErrors(result);
			return View();
		}
	}

	// If we got this far, something failed, redisplay form
	return View(model);
}

//
// GET: /Account/ResetPasswordConfirmation
[AllowAnonymous]
public ActionResult ResetPasswordConfirmation()
{
	return View();
}

Step 8: Add view ForgotPassword.cshtml

@model MvcIdentity2Migration.Models.ForgotPasswordViewModel
@{
    ViewBag.Title = "Forgot your password?";
}

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

@using (Html.BeginForm("ForgotPassword", "Account", FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
{
    @Html.AntiForgeryToken()
    <h4>Enter your email.</h4>
    <hr />
    @Html.ValidationSummary("", new { @class = "text-danger" })
    <div class="form-group">
        @Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" })
        <div class="col-md-10">
            @Html.TextBoxFor(m => m.Email, new { @class = "form-control" })
        </div>
    </div>
    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <input type="submit" class="btn btn-default" value="Email Link" />
        </div>
    </div>
}

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

Step 9: Add view ForgotPasswordConfirmation.cshtml

@{
    ViewBag.Title = "Forgot Password Confirmation";
}

<hgroup class="title">
    <h1>@ViewBag.Title.</h1>
</hgroup>
<div>
    <p>
        Please check your email to reset your password.
    </p>
</div>

Step 10: Add view ResetPassword.cshtml

@model MvcIdentity2Migration.Models.ResetPasswordViewModel
@{
    ViewBag.Title = "Reset password";
}

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

@using (Html.BeginForm("ResetPassword", "Account", FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
{
    @Html.AntiForgeryToken()
    <h4>Reset your password.</h4>
    <hr />
    @Html.ValidationSummary("", new { @class = "text-danger" })
    @Html.HiddenFor(model => model.Code)
    <div class="form-group">
        @Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" })
        <div class="col-md-10">
            @Html.TextBoxFor(m => m.Email, new { @class = "form-control" })
        </div>
    </div>
    <div class="form-group">
        @Html.LabelFor(m => m.Password, new { @class = "col-md-2 control-label" })
        <div class="col-md-10">
            @Html.PasswordFor(m => m.Password, new { @class = "form-control" })
        </div>
    </div>
    <div class="form-group">
        @Html.LabelFor(m => m.ConfirmPassword, new { @class = "col-md-2 control-label" })
        <div class="col-md-10">
            @Html.PasswordFor(m => m.ConfirmPassword, new { @class = "form-control" })
        </div>
    </div>
    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <input type="submit" class="btn btn-default" value="Reset" />
        </div>
    </div>
}

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

Step 11: Add view ResetPasswordConfirmation.cshtml

@{
    ViewBag.Title = "Reset password confirmation";
}

<hgroup class="title">
    <h1>@ViewBag.Title.</h1>
</hgroup>
<div>
    <p>
        Your password has been reset. Please @Html.ActionLink("click here to log in", "Login", "Account", routeValues: null, htmlAttributes: new { id = "loginLink" })
    </p>
</div>

 

Testing Password Reset function

Open AspNetUsers table then make sure old account has valid email and EmailConfirmed value is set to True

Run the application and test your Password Reset Function

Forgot Password page


Email Received

Reset Password page

Done!

Hope this help!

April 26, 2014

[WP8.1]: Changing Windows Phone 8.1 WebView default User-Agent in all outbound HTTP requests

Filed under: Microsoft Technology,Tips,Windows Phone — basquang @ 10:07 AM
Tags: , ,

Recently, I’m developing Windows Phone 8 app which hosting our cloud services. We need to add some custom HTTP Headers in to requests. Unfortunately, Windows Phone 8 WebBrowser control doesn’t have properties to set custom User-Agent by default. The only way you can do is the method:

webBrowser1.Navigate(new Uri("https://basquang.wordpress.com/2014/04/26/wp8-1-changing-windows-phone-8-1-webview-default-user-agent-in-all-outbound-http-requests/", UriKind.Absolute), 
null, "User-Agent: your custom user-agent");

But with this method, you are able to pass your custom user-agent in first request only. With outbound HTTP request, meaning all web link in your site, the webBrowser1 will using device’s default User-Agent.

You can check your current user-agent here: http://whatsmyuseragent.com/

By the release of Windows Phone 8.1, now you can set your custom User-Agent for entire process by using Win32 API: UrlMkSetSessionOption

Using following code to make your user-agent by default for all outbound HTTP request in WebView control on Windows Phone 8.1

[DllImport("urlmon.dll", CharSet = CharSet.Ansi)]
private static extern int UrlMkSetSessionOption(int dwOption, string pBuffer, int dwBufferLength, int dwReserved);

const int URLMON_OPTION_USERAGENT = 0x10000001;
public void ChangeUserAgent(string Agent)
   {
      UrlMkSetSessionOption(URLMON_OPTION_USERAGENT, Agent, Agent.Length, 0);
   }

void MainPage_Loaded(object sender, RoutedEventArgs e)
   {
      ChangeUserAgent("My Custom User-Agent");
      wb.Navigate(new Uri("https://basquang.wordpress.com/2014/04/26/wp8-1-changing-windows-phone-8-1-webview-default-user-agent-in-all-outbound-http-requests/", UriKind.Absolute));
   }

Hope this help!

Reference: http://www.lukepaynesoftware.com/articles/programming-tutorials/changing-the-user-agent-in-a-web-browser-control/

March 24, 2014

[Solved]: The Windows Phone Emulator wasn’t able to create the external network switches

Filed under: Windows Phone — basquang @ 11:20 AM

The error when you are try to starting Windows Phone Emulator with configuring Internet connection option

Solution: Following steps below:

  1. Disable Internet Connection Sharing on your Network Adapter

  2. Manual create Windows Phone Emulator Internal Switch

  3. Manual create Windows Phone Emulator External Switch.

    I resolved this error in my machine with configuration below:

  • Sony Vaio Tab 11
  • Hyper-V enabled in BIOS
  • Windows 8.1 Pro
  • Visual Studio 2013 Ultimate

Hope this help!

February 27, 2014

Goodle News: The Google News reader on Windows Phone

Filed under: Windows Phone — basquang @ 10:15 AM
Tags: , , , ,

Goodle News is one of the best Google News reader on Windows Phone. Google News is a free news aggregator provided and operated by Google Inc, selecting most up-to-date information from thousands of publications by an automatic aggregation algorithm.

You can easy switch to read newspaper in other country within application by selecting language. The supported countries are: United States, United Kingdom, German, France, Italy, Russia, Korea, Thailand and Vietnam.

Tiếng Việt:

Goodle Tin tức là một trong những người đọc Google News tốt nhất trên Windows Phone. Google News là nơi tập hợp tin tức miễn phí được cung cấp và điều hành bởi Google Inc, lựa chọn hầu hết các thông tin cập nhật từ hàng ngàn ấn phẩm của một thuật toán tổng hợp tự động.

Bạn có thể dễ dàng chuyển sang đọc báo trong nước khác trong ứng dụng bằng cách chọn ngôn ngữ. Các quốc gia được hỗ trợ là: Hoa Kỳ, Vương quốc Anh, Đức, Pháp, Ý, Nga, Hàn Quốc, Thái Lan và Việt Nam.

Screenshort:

Download Link

http://www.windowsphone.com/s?appid=882c1720-19ea-4ab9-a31a-f43109f75b42

GoodleNews

January 21, 2014

2013 in review

Filed under: Uncategorized — basquang @ 11:12 AM

The WordPress.com stats helper monkeys prepared a 2013 annual report for this blog.

Here’s an excerpt:

The concert hall at the Sydney Opera House holds 2,700 people. This blog was viewed about 46,000 times in 2013. If it were a concert at Sydney Opera House, it would take about 17 sold-out performances for that many people to see it.

Click here to see the complete report.

September 26, 2013

Windows Store 8.1: Save visual element to bitmap image file

Filed under: Windows Store 8 — basquang @ 3:56 PM
Tags: , , ,

If you has already familiar with Windows Phone development. You may able to capture screen or visual element to image file using the Render method of WriteableBitmap object. When develop Windows Store app, the Render method will not exist at this time. If you are developing Windows Store 8.0 application, it will not easy for you to create a screen capture programmatically of saving visual element to image file. Fortunately with Windows Store 8.1, Microsoft provides the alternative object to do this case, that is RenderTargetBitmap object.

This method below allow you to saving visual element to file (it would saved to Local Storage or Library)

 

async Task SaveVisualElementToFile(FrameworkElement element, StorageFile file)
        {
            string fileName = "customphoto.jpg";
            var renderTargetBitmap = new RenderTargetBitmap();
            await renderTargetBitmap.RenderAsync(element, (int)element.Width, (int)element.Height);
            var pixels = await renderTargetBitmap.GetPixelsAsync();

            using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.ReadWrite))
            {
                var encoder = await
                    BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, stream);
                byte[] bytes = pixels.ToArray();
                encoder.SetPixelData(BitmapPixelFormat.Bgra8,
                                     BitmapAlphaMode.Ignore,
                                     (uint)element.Width, (uint)element.Height,
                                     96, 96, bytes);

                await encoder.FlushAsync();
            }
        }

NOTE: You cannot save visual element which in code (offscreen) to image file as mention here http://social.msdn.microsoft.com/Forums/sqlserver/en-US/257a1dda-3b0c-4eec-9b08-85c1b9cda187/rendertargetbitmap-not-working-with-simple-stack-panel

Hope this help!

« Previous PageNext Page »

Create a free website or blog at WordPress.com.