Sunday, February 1, 2015

Quartz.NET usage Demo

Taken from –


1)      Download Quartz latest from http://sourceforge.net/projects/quartznet/files/quartznet/
2)      Unzip it.
3)      Copy over files from unzipped location (\server\bin\4.0\*.*)  to Program files(x86)\Quartz.Net (Need to create directory)
4)      Install the Quartz service by the running the following –
Quartz.Server.exe –install
5)      After this, it ll be listed in services.msc
6)      (optional but useful) Enable logging in Quartz by adding/modifying few lines in Quartz.Server.exe.config


    <common>
        <logging>
            <factoryAdapter type="Common.Logging.Log4Net.Log4NetLoggerFactoryAdapter, Common.Logging.Log4net">
                <arg key="configType" value="INLINE" />               
                <arg key="configFile" value="Trace/application.log.txt"/>
                <arg key="level" value="ALL" />
            </factoryAdapter>
        </logging>
    </common>
    <appSettings>
      <add key="log4net.Internal.Debug" value="false"/>
    </appSettings>
    <log4net>
        <appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
            <layout type="log4net.Layout.PatternLayout">
                <conversionPattern value="%d [%t] %-5p %l - %m%n" />
            </layout>
        </appender>
        <appender name="EventLogAppender" type="log4net.Appender.EventLogAppender">
            <layout type="log4net.Layout.PatternLayout">
                <conversionPattern value="%d [%t] %-5p %l - %m%n" />
            </layout>
        </appender>
        <appender name="GeneralLog" type="log4net.Appender.RollingFileAppender">
            <file value="Trace/application.log.txt"/>
            <appendToFile value="true"/>
            <maximumFileSize value="1024KB"/>
            <rollingStyle value="Size"/>
            <layout type="log4net.Layout.PatternLayout">
              <conversionPattern value="%d{HH:mm:ss} [%t] %-5p %c - %m%n"/>
            </layout>
          </appender>
        <root>
            <level value="ALL" />
            <appender-ref ref="ConsoleAppender" />
            <appender-ref ref="EventLogAppender" />
            <appender-ref ref="GeneralLog"/>
        </root>
    </log4net>
</configuration>


7)      Create a class library, add  Quartz nuget pkg and create a simple job my implementing IJob.
namespace QuartzMultipleJobsDemo
{
    public class OddJob : IJob
    {
        private static readonly ILog Log = LogManager.GetLogger(typeof(OddJob));

        //Empty ctor is mandatory.
        public OddJob()
         {

         }

        public void Execute(IJobExecutionContext context)       
        {           
                Log.DebugFormat("{0}****{0}Job {1} fired @ {2} next scheduled for {3}{0}***{0}",
                                                                        Environment.NewLine,
                                                                        context.JobDetail.Key,
                                                                        context.FireTimeUtc.Value.ToString("r"),
                                                                        context.NextFireTimeUtc.Value.ToString("r"));
           
        }
    }
}


8)      Build and copy the DLL to c:\Program files(x86)\Quartz.NET (created in Point 3)
9)      Modify quartz_jobs.xml to add the job and trigger. The job name is specified using namespacename.classname, assemblyname. (sample below)

<job>
      <name>EvenJob</name>
      <group>QuartzJobLib</group>
      <description>EnhancementProj - EvenJob</description>
      <job-type>QuartzMultipleJobsDemo.EvenJob, QuartzMultipleJobsDemo</job-type>
      <durable>true</durable>
      <recover>false</recover>
    </job>

 <job>
      <name>OddJob</name>
      <group>QuartzJobLib</group>
      <description>EnhancementProj - OddJob</description>
      <job-type>QuartzMultipleJobsDemo.OddJob, QuartzMultipleJobsDemo</job-type>
      <durable>true</durable>
      <recover>false</recover>
    </job>

    <trigger>
      <simple>
        <name>sampleSimpleTriggerEven</name>
        <group>sampleSimpleGroup</group>
        <description>Simple trigger to simply fire sample job</description>
        <job-name>EvenJob</job-name>
        <job-group>QuartzJobLib</job-group>
        <misfire-instruction>SmartPolicy</misfire-instruction>
        <repeat-count>50</repeat-count>
        <repeat-interval>1000</repeat-interval>
      </simple>
    </trigger>
   <trigger>
      <simple>
        <name>sampleSimpleTriggerOdd</name>
        <group>sampleSimpleGroup</group>
        <description>Simple trigger to simply fire sample job</description>
        <job-name>OddJob</job-name>
        <job-group>QuartzJobLib</job-group>
        <misfire-instruction>SmartPolicy</misfire-instruction>
        <repeat-count>50</repeat-count>
        <repeat-interval>3000</repeat-interval>
      </simple>

    </trigger>

Sunday, January 11, 2015

ASP.NET forms authentication using SQLMembership provider

First create the membership database by running aspnet_regsql. It opens up a GUI and you can specify the database server, database name, account under which all will run.

At the code level –

[HttpPost]
        public ActionResult Login(LoginViewModel model)
        {           
            var isValidated = Membership.ValidateUser(model.Username, model.Password);
            if (isValidated)
            {
               FormsAuthentication.SetAuthCookie(model.Username, true);
               return RedirectToAction("Index", "Home");
            }
              else
            {
               //show error message
     }
        }


public ActionResult Logout()
        {
            FormsAuthentication.SignOut();
            return View("Login");
        }



Login view

@model FormAuthDemo.Models.LoginViewModel
@{
    ViewBag.Title = "Login";
}

<h2>Login</h2>

@using (Html.BeginForm("Login", "Account", FormMethod.Post))
{
    <div>
        @Html.LabelFor(u => u.Username)
        @Html.TextBoxFor(u => u.Username)
    </div>
    <div>
        @Html.LabelFor(u => u.Password)
        @Html.TextBoxFor(u => u.Password)
    </div>
    <div>
        @Html.LabelFor(u => u.RememberMe)
        @Html.CheckBoxFor(u => u.RememberMe)
    </div>
     <div>
        <input type="submit" value="Login" />
    </div>
}



Logout usage (in Home > Index view)

@{
    ViewBag.Title = "Index";
}

<h2>Index</h2>

Home-Index-Only Authenticated users allowed
<div>
     @Html.ActionLink("Log Out", "Logout", "Account")
</div>



Web.config sample


<?xml version="1.0" encoding="utf-8"?>
<!--
  For more information on how to configure your ASP.NET application, please visit
  http://go.microsoft.com/fwlink/?LinkId=152368
  -->
<configuration>
  <configSections>
    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
  </configSections>
  <connectionStrings>
    <add name="DemoMembershipDBConn" providerName="System.Data.SqlClient" connectionString="Data Source=MikePC;Initial Catalog=DemoMembershipDB;Integrated Security=SSPI" />
  </connectionStrings>
  <appSettings>
    <add key="webpages:Version" value="2.0.0.0" />
    <add key="webpages:Enabled" value="false" />
    <add key="PreserveLoginUrl" value="true" />
    <add key="ClientValidationEnabled" value="true" />
    <add key="UnobtrusiveJavaScriptEnabled" value="true" />
  </appSettings>
  <system.web>
    <httpRuntime targetFramework="4.5" />
    <compilation debug="true" targetFramework="4.5" />
    <authentication mode="Forms">
      <forms loginUrl="~/Account/Login" timeout="2880" cookieless="UseCookies" />
    </authentication>
    <authorization>
      <deny users="?" />
      <allow users="*" />
    </authorization>
    <pages>
      <namespaces>
        <add namespace="System.Web.Helpers" />
        <add namespace="System.Web.Mvc" />
        <add namespace="System.Web.Mvc.Ajax" />
        <add namespace="System.Web.Mvc.Html" />
        <add namespace="System.Web.Optimization" />
        <add namespace="System.Web.Routing" />
        <add namespace="System.Web.WebPages" />
      </namespaces>
    </pages>
    <profile defaultProvider="DefaultProfileProvider">
      <providers>
        <add name="DefaultProfileProvider" type="System.Web.Providers.DefaultProfileProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="DemoMembershipDBConn" applicationName="/" />
      </providers>
    </profile>
    <membership defaultProvider="DefaultMembershipProvider">
      <providers>
        <add name="DefaultMembershipProvider" type="System.Web.Providers.DefaultMembershipProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="DemoMembershipDBConn" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" applicationName="/" />
      </providers>
    </membership>
    <roleManager defaultProvider="DefaultRoleProvider">
      <providers>
        <add name="DefaultRoleProvider" type="System.Web.Providers.DefaultRoleProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="DemoMembershipDBConn" applicationName="/" />
      </providers>
    </roleManager>
    <!--
            If you are deploying to a cloud environment that has multiple web server instances,
            you should change session state mode from "InProc" to "Custom". In addition,
            change the connection string named "DefaultConnection" to connect to an instance
            of SQL Server (including SQL Azure and SQL  Compact) instead of to SQL Server Express.
      -->
    <sessionState mode="InProc" customProvider="DefaultSessionProvider">
      <providers>
        <add name="DefaultSessionProvider" type="System.Web.Providers.DefaultSessionStateProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="DefaultConnection" />
      </providers>
    </sessionState>
  </system.web>
  <system.webServer>
    <validation validateIntegratedModeConfiguration="false" />
    <handlers>
      <remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" />
      <remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
      <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
      <add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
      <add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
    </handlers>
  </system.webServer>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="EntityFramework" publicKeyToken="b77a5c561934e089" />
        <bindingRedirect oldVersion="0.0.0.0-5.0.0.0" newVersion="5.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-1.3.0.0" newVersion="1.3.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
  <entityFramework>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
      <parameters>
        <parameter value="v11.0" />
      </parameters>
    </defaultConnectionFactory>
  </entityFramework>
</configuration>



The important blocks in web.config are marked in yellow background – namely the connectionstring of the membership database, the <authentication> tag which specifies “Form” and login URL. This is the url where every unauthenticated user will be redirected to.


The <authorization> tag above states that allow all “authenticated” users and deny all “unauthenticated” users. The <membership> tag contains the membership provider to be used and also refers the connectionstring declared above.


Some other points are –

User.Identity.IsAuthenticated won't be set to true until the next request after calling FormsAuthentication.SetAuthCookie().

To add users, roles etc, you can use the GUI (browser based) provided by Visual Studio. Assuming the connectionstring in your web.config are valid, it ll open up GUI with wizard to add users, roles.