Sunday, February 28, 2016

Properly invoking scheduled WebJobs

Recently we've found the need to start using Scheduled Azure WebJobs. However, the examples out there are all gargbage, even in the case where you can find an actual example using a scheduled WebJob rather than a continuous WebJob. So, for the benefit of anyone interested, including future me, here's the proper way to invoke a Scheduled WebJob in the entry point of the WebJobs assembly:

    /// <summary>
    /// The main entry point to the scheduled webjobs.
    /// </summary>
    public class Program
    {
        /// <summary>
        /// Main entry point for the scheduled webjobs
        /// </summary>
        public static void Main()
        {
            IKernel kernel = new StandardKernel();

            kernel.Load(new ServicesScheduledWebJobsNinjectModule());

            var jobHostConfiguration = new JobHostConfiguration
            {
                JobActivator = new ServicesScheduledWebJobsActivator(kernel),
                DashboardConnectionString = ConfigurationManager.ConnectionStrings["AzureWebJobsDashboard"].ConnectionString,
                StorageConnectionString = ConfigurationManager.ConnectionStrings["AzureWebJobsStorage"].ConnectionString,
            };

            var host = new JobHost(jobHostConfiguration);

            // Must ensure that we call host.Start() to actually start the job host. Must do so in
            // order to ensure that all jobs we manually invoke can actually run.
            host.Start();

            // The following code will invoke all functions that have a 'NoAutomaticTriggerAttribute'
            // to indicate that they are scheduled methods.
            foreach (MethodInfo jobMethod in typeof(Functions).GetMethods().Where(m => m.GetCustomAttributes<NoAutomaticTriggerAttribute>().Any()))
            {
                try
                {
                    host.CallAsync(jobMethod).Wait();
                }
                catch (Exception ex)
                {
                    Console.Error.WriteLine("Failed to execute job method '{0}' with error: {1}", jobMethod.Name, ex);
                }
            }
        }
    }

What the above does is the following:

  • Configures the JobHost to use a dependency injection container via a custom IJobActivator implementation that, in our case, uses the Ninject dependency injection container.
  • Configures the JobHost with a custom configuration so that we can control various items, including the connection strings for the dashboard and jobs storage.
  • Starts the JobHost. This bit is important, because all the other examples out there neglect that this needs to be done.
  • Dynamically resolves all schedulable methods that should be invoked, using the NoAutomaticTriggerAttribute built in to the WebJobs SDK. This attribute is used internally by the SDK to determine which methods need to be invoked manually (i.e. on demand) rather than by a continuous invocation used by Continous WebJobs.

Continuous Delivery of Azure Web Services

See this:

https://azure.microsoft.com/en-us/documentation/articles/cloud-services-dotnet-continuous-delivery/

Sunday, February 21, 2016

Debugging Azure web apps on localhost

To get this working, you need to have an app registered with your localhost app root registered for the redirect URI and login URI. Here's the really important part of you're using AAD authentication:

You need to disable all forms of Authorization in IIS and enable Anonymous authentication for the application in the IIS manager on the web app itself so that Azure AD can take over the authentication!

Using adal.js and getting error AADSTS65001: The user or administrator has not consented to use the application with ID '....'

It turns out that you have to actually go in and give your javascript web client permissions to access the web api application in the Azure Active Directory management portal. Go figure.

Using adal.js and getting error AADSTS70005: response_type="token" not supported

I've recently started using adal.js with OData in an AngularJS 1.5 application and been getting this error with attempting to connect my client-side XHR requests to my Web API application.

Following the advice here, changing the AAD manifest of the AngularJS web client from this:

"oauth2AllowImplicitFlow": false

... to this:

"oauth2AllowImplicitFlow": true

... seems to have solved the problem.

Tuesday, February 16, 2016

Getting CORS requests working in Web API 2

I've just recently started playing with using adal.js to connect to Azure Active Directory for authentication so that I can set up an AngularJS => Web API scenario with OData connections.

I followed the page on asp.net here.

However, I'm still running into the following problem: // TODO

Monday, February 08, 2016

How to move a shelveset from one branch to another in TFS

You're going to have to start by installing the TFS PowerTools for TFS 2013 (or whatever version is appropriate for you). Once you have the powertools installed and the tools added to your PATH (if they're not already added by the installer), run a command similar to the following in the command line:

tfpt unshelve /migrate /source:"$/ProjectName/Branch" /target:"$/ProjectName/Targetbranch" "My Shelveset Name"

This will unshelve your shelveset into your new branch for you.

WARNING: Before you do this, make sure you're unshelving into a clean branch with no Pending Changes, otherwise you could inadvertently overwrite or otherwise lose important changes.