Assumptions

Overview

One of the challenges I had when learning Dynamics 365 / Power Platform development was how to add custom functionality to the User Interface. The .NET developer in me was frustrated when I wanted to add a button to the page that triggered some server-side code. Eventually, I learned a pattern of adding HTML / JavaScript resources to the page that would create an Annotation (Note). A plugin would intercept the Annotation and get the Regarding object. This would allow me to trigger server-side code from the User Interface, but it was not as graceful as I would have liked. A colleague of mine, Patrick O’Gorman, told me about Power Apps Component Framework (PCF) controls for some time, and I recently decided to start experimenting with them. In this blog post, I will illustrate how I could use a PCF control to trigger a flow in Power Automate.

Creating the PCF Control

Before creating the control, I recommend reviewing both the Microsoft Learning Paths for Power Platform Component Framework and Patrick O’Gorman’s PCF Demo.

I begin by creating a folder to house the project and then follow these steps:

  • Open Visual Studio (VS) Code
  • In VS Code, Open the folder that was created for the project
  • Click View and then TerminalIn the terminal window, I do the following:
  • Initialize the project: pac pcf init –namespace PCFControls –name PCFFlowTriggerDemo –template field
  • Install TypeScript: npm install typescript
  • Build the project: npm run build
  • Run the project: npm start

When I run the project, the PCF Control Sandbox opens. It is empty at this point, but not for long.

Empty PCF Control

I close the Sandbox window and use CTRL+C to terminate the Sandbox in the terminal window.

Creating the Power Automate Flow

For this project, I will set the control to the side for now and create the flow because I will want the endpoint created to use in control. For this example, I will create a simple workflow that receives a Contact Id from the PCF Control and then emails the Contact. I realize there are better methods for emailing a client within the Model Driven App, but this is just an example. I create this flow by following these steps:

Configure the Trigger

Login to Power Automate

Create New Flow and choose Instant cloud flow

Create New Flow and choose instant cloud flow

Enter the name of the flow and choose When an HTTP request is received (Request) for the trigger.

Build and instant cloud flow

When the flow opens, expand the trigger and select Use sample payload to generate schema.
Use the following JavaScript Object Notation (JSON)
{ “contact” : { “contactid”: “00000000-0000-0000-0000-000000000000”} }

Enter or paste a sample JSON payload

Click Done and the schema generates:

When HTTP request is received

Check the Origin

Next, I verify that the request’s origin is from my Power App. This prevents someone from using PostMan, Fiddler, etc. to build a request and hit the endpoint maliciously.

Click New Step > Control > Condition
Click left-hand Choose a value > Expression and enter the following:
triggerOutputs()[‘headers’][‘origin’]

Choose a Value and Expression

Click left-hand Choose a value and enter the root URL for Power App (ex. https://orgc76a7275.crm.dynamics.com)

Email the Contact

Inside of the Yes condition, click Add an action > choose Microsoft Dataverse as the connector and then Get a row by ID.
Select Contact as the table and select the contacted from Dynamic content in the Row ID field.

Select contact as the table

Inside the Yes condition, click Add an action > type Outlook, select Office 365 Outlook as the connector type, and then Send an email.
Click To > Add dynamic content and then select Email.

Send an email

I fill in other required fields to send a test email.

Send a test email

Click Save

Get the POST URL

Now that the flow is complete and we have saved it, the POST URL is made available. I scroll back up to the top of the flow and expand the trigger; I copy the URL and save it later.

HTTP Post URL

Triggering the Flow from the Control

Now that I have the PCF control project in place and the flow complete, I can finish the control. I return to VS Code, open the index.ts, and perform the following steps:
I want to add a variable for the current context and the container that I will be using to build our control. Add the following lines just above the constructor.

               private _context: ComponentFramework.Context<IInputs>;
              private _container: HTMLDivElement;

Triggering the Flow from the Control

Next, I need to create an HTML Div element, add a button, and add an event listener for the click event. Locate the init method and replace the code inside with the following lines:

                              this._context = context;
                             this._container = document.createElement("div");
               container.appendChild(this._container);
 
                             let button: HTMLButtonElement = document.createElement("button");
                             button.id = "cf6e3bc1-1cc1-4404-9171-9b7c981f97f6"
                            button.innerHTML = "Email Contact";
 
               button.addEventListener("click", this.emailContactOnClickHandler.bind(this));
                     this._container.appendChild(button);
 

Triggering flow from control

Finally, I need to add the click event handler. This code gets the Id of the current Id of the record, builds the JSON payload that I used earlier, posts it to the URL from our flow, and disables the button (to prevent spamming it). Below the destroy method but inside the class, add the following method:

	private emailContactOnClickHandler(event: Event): void {
		var context = this._context;

		var contactId = (<any>context).page.entityId;
		var contactPayload = '{ "contact" : { "contactid": "' + contactId + '"} }';

		var req = new XMLHttpRequest();
		var url = "[URL FROM FLOW]";
		req.open("POST", url, true);
		req.setRequestHeader('Content-Type', 'application/json');
		req.send(contactPayload);

		let button = document.getElementById("cf6e3bc1-1cc1-4404-9171-9b7c981f97f6")
		if (button) {
			(button as HTMLButtonElement).innerHTML = "Email Sent...";
			(button as HTMLButtonElement).disabled = true;
		}
	}

Destroy Method

You may have noticed that I am using a GUID for the button; there is nothing special about this GUID, and any can be used. I just needed a unique Id for the button control to retrieve it later. I also left out the URL from the flow; this should be the value created when the flow was saved. Now I can build and run the project:

  • Build the project: npm run build
  • Run the project: npm start

When I run the project, the PCF Control Sandbox opens, and we can see our button element now.

Power Apps Test Environment

I close the Sandbox window and use CTRL+C to terminate the Sandbox in the terminal window.

Deploying the PCF Control

Now I am ready to deploy the control of my Model Driven App; in this case, I am using a Dynamics 365 Sales Trial. I deploy the new control by doing the following:

Publishing the Solution

  • In the terminal window, I authenticate with my App: pac auth create –url https://orgc76a7275.crm.dynamics.com
  • I build the project: npm run build
  • When the login window pops up, I enter my credentials
  • I deploy the solution: pac pcf push –publisher-prefix ais

Adding the Control to the UI

I click on the gear, select Advanced Settings.

Advanced Settings

I click the drop-down next to Settings and then click Customizations and then Customize the System.

Customize the System

Note: Normally, I would use a custom solution instead of Customize the System. When I use Customize the System, I am editing the default solution that I am not concerned about for this example.

In the Solution window that opens, I expand Entities, locate and expand Contact, select Fields, and then click New.

Contact Fields

For the Display Name, I use “PCF Email Contact” and change Searchable equal to false; this will prevent the field from appearing as a search as an option. This field will serve as a placeholder for my control. I leave everything else as-is and click Save and Close.

PCF Email Contract

In the Solution, select Forms and then open the form. In my case, the entity is configured to use the Sales Insights by default, so I will edit it.

Sales Insights

In the form window that opens, I locate my newly created field and drag it right below the Email field.

New Field with Email

I double-click on the field, uncheck the Display label on the form, and then select the Controls tab.

Display label on the form

In the window that pops up, I can see my new control.

Add PCF Trigger Control

I select it and click Add.
In the Field Properties window, I tick the options Web, Phone, Tablet and click Ok.

Field Properties

In the form window, I click Save and Close.
In the Solutions window, I click Publish All Customizations.

PCF Control in Action

Now that I have the PCF control deployed and the flow waiting for a POST request, I am ready to test. I have created a Contact record with my email address, and now when I edit it, I see the Email Contact button.

PCF Control in Action

When I click it, it is disabled and changes to Email Sent.

Disable and Send Email

When I navigate to Power Automate I see that my flow has been completed successfully.

Successful flow completed

Finally, I check my email and it is correct.

Check email

Conclusion

As you can see, wiring up a control to your Power App with server-side logic is easy with Power Platform. Power Automate provides you with fantastic low / no-code solutions, and the Power Apps Component Framework makes it easy to design, publish and connect controls to your user interface.

You are about to start and new C# project and have opened Visual Studio. Let’s discuss some best practices you should employ or consider before writing that first line of code. These practices are just a start. I have scoped this blog post to only cover those best practices to those that can be enabled before you write a single line of code and utilize the built-in features of Visual Studio and VS Code. Of course, there are other best practices you should follow, such as unit testing, code coverage, continuous integration, etc. and other tools you may consider acquiring, but those are out of scope for this blog post.

These best practices are gleaned from years of experience developing C# solutions. First, let me present my comprehensive list of practices, then we can dive into each one individually. I will be assuming you are using .NET Core 3 and Visual Studio 2019 or later for each of the below practices. Most of the below practices are still recommended for earlier versions of .NET and Visual Studio but may be configured differently.

  1. Turn on Warnings as Errors
  2. Turn on Code Analysis
  3. Establish Code Conventions
  4. Consider Enabling Nullable Reference Checking

1. Turn on Warnings as Errors

Why?: You might think that having warnings is enough. However, even for some of the most diligent programmers on a project, they might have a bad day and miss a warning message from the compiler or forget to fix it before committing code to a project. Instead of relying on human discipline, why not merely automate that discipline by asking for the compiler’s assistance. By enabling warnings as errors, every compiler warning will now manifest as an error preventing compilation until addressed. As a developer, you can still disable alerts at the entire project level, or you can #pragma directives to disable warnings for given cases in the codebase. In either case, you now have an affirmative decision in the codebase that can be traced back with version history. It would be best if you considered asking developers to include comments explaining why the warning was disabled. This is the single biggest thing I do when starting any C# project. It keeps unfixed warnings from ever entering my codebase.

How?: You can right-click on a Project in Visual Studio and select “Properties…”. On the properties screen, you can navigate to the Build tab. On the Build tab, be sure and use the drop-down for Configuration to select “All Configurations.” Then, under the Treat warnings as errors, select “All” for the radio button and save the project. You can reference the screenshot below.

Set configurations for new project

For those of you on Linux/MacOS X or using VSCode, you can instead open the .csproj file directly in a text editor. You can then add the following code inside the top-level tag:

<TreatWarningsAsErrors>true</TreatWarningsAsErrors>

See the screenshot below:

Warning as Errors Screenshot

2. Turn on Code Analysis

Why?: Let’s talk about compiler warnings and errors first. Compiler errors are typically there because you made a syntax error, and the compiler can’t generate any code. Compiler warnings are provided typically because the compiler may be a deciding factor, but isn’t sure of your intention, hence a warning that they hope you will read and then fix. Most compiler teams are wary of adding new errors because it will discourage upgrades to a new compiler version. So, most of the time, compiler teams will only add recent warnings to a compiler, and by default, those warnings can be disregarded. But in general, I like to consider new compiler warnings as errors the compiler team wished they could have written. Hence, the rationale in the previous section for always enabling warnings as errors.

Now, let’s continue with the viewpoint that compiler warnings are errors, just left as warnings because the compiler team was worried about upgrades to new compiler versions and backward compatibility. With that viewpoint, warnings are still essentially only pointing out significant faults in your codebase; they aren’t pointing out suggestions or even best practices. So, how can we get recommendations or best practices? The answer to that question is to enable Code Analysis and then configure your desired ruleset.

How?: You can right-click on a Project in Visual Studio and select “Properties…”. On the properties screen, you can navigate to the Code Analysis tab. On the Code Analysis tab, click the Install button. The install button will download a NuGet package that contains the code analysis rules. In general, leave both checkboxes enabled. This ensures rules during a full build of the project, and the rules built as you are typing live in the editor. You can reference the screenshot below.

Download nuget package that contains code analysis

For those of you on Linux/MacOS X or using VSCode, you can instead open the .csproj file directly in a text editor. You can then add the following code inside a new tag:

<PackageReference Include=”Microsoft.CodeAnalysis.FxCopAnalyzers” Version=”2.9.6″>

See the screenshot below.

Turned on Code Analysis

If you have enabled Warnings as Errors as recommended in the previous section, the Code Analysis rules will be considered compiler errors.

What to do once you’ve turned on Code Analysis

Let’s imagine you have created a new console application using the provided templates. Now imagine you followed my recommendations and enabled warnings as errors and turned on code analysis. Now, if you compile that application for the first time, you immediately see 2 Code Analysis errors, and your project will no longer compile. See the screenshot below.

Compile Application and see 2 Errors

Keep in mind all you’ve done is used a provided template project and turned on some Code Analysis rules. You haven’t added any code to the project. Why then, do we see two errors in the code? Let’s talk about each error individually. As you see, the codes for the rules are CA1801 and CA1303.

Fixing Code Analysis Error #1 – CA1801 Unused Argument

How can we fix this code analysis suggestion/error, and what does it mean? The first suggestion is CA1801, which tells us that our Main method accepts a string array of arguments but that we aren’t using them in the method body. This is precisely the kind of assistance we are looking for. In this case, we could remove the arguments to the Main method. This makes our intention clearer; our Console application doesn’t have any arguments.

However, if we were implementing an interface, we might be required to have that argument even though our implementation isn’t using that argument. In this case, we can disable this on a case-by-case basis using #pragma directive. We can disable this by adding the following code around the statements where we want the rule disabled.

#pragma warning disable CA1801 // Remove unused parameter
//other code goes here
#pragma warning restore CA1801 // Remove unused parameter

You can also reference the below screenshot.

Add code to disable rule

Any code between the #pragma disable, and the restore will not be checked for that given code analysis rule. The developer could also provide comments as to why this choice was made. But it’s now clear and has an intention behind it. This same approach can be used for general compiler warnings that were turned on as errors in the previous section.

Fixing Code Analysis Error #2 – CA1303 Globalization

Now, let’s talk about the second code analysis error/suggestion, which is CA1303. This rule was built because internally, Microsoft is required to run it. Microsoft is a multinational company, and they deliver software to many countries in many languages. The CA1303 code analysis warning indicates that we have a hard-coded string, and we should move it to the resource (.resx) file where we could map different versions of the string depending upon the requested language and culture. Now, for our given project, it’s good that Code Analysis pointed this out so early. Because we encountered this error so early in our project, we can ask our requirements team if we need to support globalization. However, let’s assume our requirements team decides we don’t need to perform globalization. How can we turn this off once and not have to litter our code with hundreds of #pragma’s? The answer to that question is to use .editorconfig files. For those working in .NET for many years or before .NET Core, the use of .editorconfig is relatively new but is far easier than the older alternatives. The easiest way to get started is to let Visual Studio help you out. If you right-click on the Lightbulb icon for the given line, you can click to Suppress or Configure Issues. Within that menu, you can Configure CA1303 severity. When you select that option, regardless of the value, it will offer to create a new .editorconfig and add it to your project. See the screenshot below for reference.

create a new .editorconfig and add it to your project

For those of you on Linux/MacOS X or using VSCode, create a new file named .editorconfig with the following contents:
[*.cs]
# CA1303: Do not pass literals as localized parameters
dotnet_diagnostic.CA1303.severity = none

Once you have an .editorconfig, if you are using Visual Studio, you can view all of the analysis rules and configure them individually. In the Solution Explorer, expand your project. Then expand the Dependencies node and under that expand the Analyzers node. You can then find a given rule and right-click to configure Severity. This will then add a new line to your .editorconfig. See the below screenshot.

New line added to .editorconfig

Code Analysis Summary

To summarize, enable Code Analysis. It would be best if you then fixed any code analysis errors or decide you have a good reason for not fixing the suggestion. If you have a good cause, you can use #pragma directives to disable on a case-by-case basis, or you can .editorconfig to disable entire rules.
The .editorconfig works on a directory basis. The compiler will walk up directories from the source file until it finds a .editorconfig file. So, you can stack rules for your entire solution while having different rules for unit test projects, for example.
You can also write custom code analysis rules and find other open-source packages with custom code analysis rules. You should research to see if any of the third-party dependencies also provide code analysis packages.

Establish Code Conventions

Why?: As you start work on a project, you are implicitly making some code style conventions. You are deciding how indentation is formatted, whether the project will use the “var” keyword, the preferred syntax for initializing collections, etc. It would be nice to automate enforcement of some decisions and have the compiler or formatting tool to help enforce these decisions. In previous years, your only option was to find a third-party tool, either free or commercial. With a more recent version of Visual Studio and VS Code, there are built-in tools that provide some of this capability for free. So, let’s take advantage of those provided features. The benefit of code conventions is enabling consistency across projects and making it easier to start working on an existing project. To that end, I would recommend you begin with well-established code conventions like those provided by Microsoft and only diverge where necessary for your project or organization.

How?: If you agree with the Why section above, let’s talk about How. All you need to do is use Visual Studio’s built-in support for .editorconfig. If you’ve been following my guidance from earlier sections, you should already have an .editorconfig file. That’s it, and you are done. As your team makes decisions, apply the setting to your .editorconfig file. Visual Studio then provides several tools to help you update code to match your agreed-upon conventions.

References:
https://docs.microsoft.com/en-us/visualstudio/ide/create-portable-custom-editor-options?view=vs-2019
https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-language-conventions?view=vs-2019

4. Consider Enabling Nullable Reference Checking

Why?: One of the largest sources of errors in running codebases is unchecked null values, which throw a NullReferenceException. I’m not suggesting you add if (x != null) checks all over your codebase, which can also have unintended consequences and can make your code harder to read. Instead, I might suggest you utilize a new C# 8 feature, which is nullable references checked by the compiler using advanced flow analysis at compilation time. This feature can be retrofitted onto an existing project, but the work is considerable and can be very confusing. But since this best practice guidance is for new projects, I would suggest you strongly consider enabling this on new projects from the beginning.

How?: To enable nullable reference checking, simply right-click on the project in Visual Studio. Then navigate to the Build tab and select “Enable” from the drop-down for the Nullable field. See the screenshot below for reference.

Enable nullable reference checking

For those of you on Linux/MacOS X or using VSCode, you can open your .csproj in a text editor and add the following to the existing tag:

<Nullable>enable</Nullable>

See the below screenshot.

Insert the Nullable group tag

Once this setting is enabled, any reference type (e.g. string name, Dictionary<string, string> properties) is now considered to be non-null the compiler and the compiler will enforce this. If you wish to permit a null value, you must annotate the type like the long-time support for nullable value types. You would need to use (string? name, Dictionary<string, string>? properties). At this point, the compiler will warn you if you attempt to use any part of the object without first checking for null. It provides advanced flow analysis to determine this and supports many of the well-known patterns you already have been using for years to check for null.

Summary

I hope you found the above guidance around best practices useful. Remember, the above best practices are simply a starting point and intended to be steps you take before writing a single line of code and are enabled using only built-in features of Visual Studio or VS Code. It would help if you considered techniques such as unit testing, code coverage, and continuous integration, and potentially using other free or commercial tools such as Resharper or CodeIt.Right.

The goal for all the above practices is to ensure you start a new project out on the best foot and ensure high code quality from the beginning of the project. By creating early, it should be a low effort to maintain high code quality. It should also result in code with fewer bugs, which always makes users happy and should result in easier code because intentions in the code are clear.

If you want to skip reading the text that follows and simply want to download Visual Studio Code Snippets for Azure API Management policies, click here.

Azure API Management gives you a framework for publishing your APIs in a consistent manner with built-in benefits like developer engagement, business insights, analytics, security, and protection. However, the most powerful capability it offers is the ability to customize behavior of the API itself. Think of the customization as a short program that gets executed just before or after your API is invoked. The short program is simply a collection of statements (called policies in Azure API Management). Examples of policies that come out of the box include format conversion from XML to JSON, applying rate and quota limits and enforcing IP filtering. In addition, you have control flow policies such as choose that is similar to if-then-else, or a switch construct and set-variable that allows you declare a context variable. Finally, you have the ability to write C# (6.0) expressions. Each expression has access to the context variable, as well as, allowed to leverage a subset of .NET Framework types. As you can see, Azure API Management policies offer constructs equivalent to a programming language.

This begs the question, how do you author Azure API Management policies?

Well, today you have two options. Read More…

visualstudio-wallpaper-05At one point I was coding on a hobby project, using Visual Studio Online for project management and source control. Because of the technologies involved, a large number of temporary files were being generated that I didn’t want checked in. Visual Studio’s TFS integration is pretty good at automatically filtering these kinds of files out and placing them in the Excluded Changes list in the Pending Changes window, but in my case the sheer number made it a pain to scan the Excluded Changes list for valid changes that I actually wanted to commit.

In my case, I didn’t want those temporary files to show up at all – not even in the Excluded Changes list. In order to gain control over which files TFS should ignore completely, I added .tfignore files to my solution. These allow you to specify which files, extensions and directories to ignore (or un-ignore!) from source control. If you’re familiar with the concept of .gitignore files in GIT, you should feel right at home.

Read More…

At AIS, our Account Teams work with our clients every day to produce IT solutions that solve business problems. We work closely with our CTO organization to ensure that we are researching the latest technology and services in a manner that is applicable to our clients and prospective clients.

We recently applied this to a business problem that required an organization to quickly — and with no notice — stand up a website to collect hundreds, or potentially millions, of submissions from the general public.  Our use case focused on law enforcement and the sorts of emergency response situations we’ve seen all too often in the news, such as the Boston Marathon bombing.  When local, state or federal authorities respond to criminal acts, they seek to quickly collect vast amounts of input from the public.  This input can be in the form of tips, photos, videos or any untold number of observations.  Agencies need the capability to surge their IT tools and applications to collect the data, store it, and run analysis tools against the collected content to harvest information. Read More…

Have you ever worked on a project that seemed to eat any memory available? If so, chances are you have encountered a memory leak. Memory leaks in SharePoint are very common. For example, using instances of SPLimitedWebPartManager can be a cause of memory leaks. Why? Turns out that SPLimitedWebPartManager instances instantiate their own SPWeb object, but don’t properly dispose of them: a bug in the SharePoint 2010 SDK. It seems that one of the only ways to discover this ghost memory leak is in production. Or a little utility, built by Microsoft, called SPDisposeCheck.

You can run SPDisposeCheck in the command line, but I thought it would be nice to integrate it into a project. These are the steps to integrate SPDisposeCheck into a build: Read More…

On Dec 6th, Brian Keller published an updated version of his very useful virtual machine and the corresponding hands-on-lab / demo scripts for Visual Studio 2012 Update 1.

This virtual machine includes existing (but upgraded) labs from 2010, as well as labs based on new features (see screenshot below).

I thought it would be nice to simply upload the VHD directly to Azure Blob Storage and provision an Azure PersistentVM based on it. This is surely the easiest way to try all the new ALM features.  And it almost worked! Except that the firewall on the virtual machine is turned on. As a result, I could not RDP into the Azure-based machine.

Read More…

It should come as no surprise that Microsoft’s strategy for SharePoint 2013 is cloud-based, SaaS, Hosted Services or whatever you want to call it.  Whatever the name, the outcome is that custom, server-side code is no longer the way to go in the SharePoint world.  This brings into question the fate of one of the workhorses of SharePoint since 2003: the Event Receiver.  Microsoft has done a great job of exposing web services and creating the Client Side Object Model to enable scripting, but that doesn’t work when your application needs to react to an event that occurs in SharePoint.

SharePoint workflow could provide some of that functionality, but there is an overhead cost to workflow.  When architecting a SharePoint-based solution and the question “Workflow or Event Receiver?” comes up, I always prefer event receivers until it’s proven that the process needs a workflow.  If all the process needs to do is fire off an e-mail or update a field in another list or database, then why incur the overhead of a workflow when an event receiver will do the job with minimal management and overhead?  But that doesn’t work in an app for SharePoint or in a hosted environment that doesn’t allow custom code…or does it?

I’m guessing you can tell from the title of this post what the answer to that is — yes, with remote event receivers.

Read More…

You’ve had a sip of the NuGet Kool-Aid, picked your jaw up off the ground after seamlessly installing your favorite Open Source project, and now you’re diving head first into NuGet as your team’s dependency management tool of choice. Private NuGet repository is in place, Package Restore is enabled and new packages are being published automagically from your builds.

DLL-hell is behind you right?  Not so fast.  This never-ending saga has reemerged as NuGet-hell.

Managing your dependencies requires discipline and conscious decision making regardless of the tools you choose.  Don’t leave the building blocks of your applications to chance.

But how do you get the information necessary to make these decisions?

Read More…

Happy Friday! Here are some of the latest posts by AIS employees from around the web and their personal blogs:

Using Git-Tf: Suppress the TFS Warning When Loading a Solution: Using Git-TF? Getting annoying TFS warnings in Visual Studio? Senior Software Engineer Kip Streithorst can help. (It’s Null?)

Fight Clutter and Confusion in the Workplace. The Importance of Process Streamlining and How to Do It: Developer Terra Gilbert has discovered a natural knack for process streamlining and improving documentation. Here are her tips. (codeterra)

Recent Items in Windows 8: Oskar Austegard plays around with a new Windows 8 install and solves the case of the missing (or at least hard-to-find) Recent Items folder. (mo.notono.us)

KnockoutJS & ASP.NET Mvc Partial View Loading: How to dynamically load “partial views” bound to KnockoutJS view models. (Null != Steve)

Scrum Fundamentals Recording Available: In case you missed Ryan Cromwell‘s Scrum Fundamentals webinar, the presentation is available on his blog. (And be sure to check our Events page — we add new events every week!) (cromwellhaus)