Wednesday, July 25, 2018

ASP.NET Core 2.1 Re-target to Full Framework 4.7.1

I am in the middle of upgrading one of my websites from ASP.NET 4 to ASP.NET Core 2.1 using Razor Pages and I absolutely love everything about the new development experience. I also upgraded all my libraries to use an appropriate .net standard version, but I was unable to upgrade one project due to the differences in how WindowsAzure.Storage nuget package is used when targeting full framework vs .netstandard. Too much had to be re-written so I just left that one library targeting full framework. However, when I tried to bring that dependency into the ASP.NET Core 2.1 site, it would not work since I was targeting netcoreapp2.1 and the WindowsAzure.Storage package ran into "Missing Method Exceptions". At this point, I had to either update the one library or update the site to target full framework. Long term, I want to update the library. Short term, I need to get past this problem, so re-targeting it is.

Retargeting

I had hoped that I could just change the TargetFramework element in the project file to net471, but that did not work. I was getting an error Package Microsoft.AspNetCore.App 2.1.0 is not compatible with net471 (.NETFramework,Version=v4.7.1). Package Microsoft.AspNetCore.App 2.1.0 supports: netcoreapp2.1 (.NETCoreApp,Version=v2.1) From there, I figured there were a different set of packages, so I created a new project targeting full framework and compared the project files. I noticed the following packages that I needed to use instead of Microsoft.AspNetCore.App. So here's what I had to change (note, I'm using a different Identity provider so I removed Entity Framework packages that were included by default):

Target Framework: netcoreapp2.1 => net471
Packages: Microsoft.AspNetCore.App =>
"Microsoft.AspNetCore" Version="2.1.1"
"Microsoft.AspNetCore.Authentication.Cookies" Version="2.1.1"
"Microsoft.AspNetCore.CookiePolicy" Version="2.1.1"
"Microsoft.AspNetCore.HttpsPolicy" Version="2.1.1"
"Microsoft.AspNetCore.Identity.UI" Version="2.1.1"
"Microsoft.AspNetCore.Mvc" Version="2.1.1"
"Microsoft.AspNetCore.StaticFiles" Version="2.1.1"

After these updates to the project file, I was able to compile and run and my full framework library was able to be used with no problem.

Thursday, March 29, 2018

Knockout datalist binding when input selected

I recently had the need to know when an item from a datalist was selected vs a user entering text into the input so that I could trigger a different behavior in the UI. This is what I came up with based on the 'input' event that is raised. When raised due to the user typing, the event's originalEvent property is an InputEvent and has an inputType property. If the user selects a value, the event's originalEvent property is an Event and does not have that property. Not sure if there's a better way, but this works! :)

    /**
     * @desc This binding will trigger when a user selects an item from
     * the data list and will pass the selected value to the specified function
     *
     */
    ko.bindingHandlers.datalistInput = {
        init: function (element, valueAccessor) {
            $(element).on('input', function (e) {
                if (e && e.originalEvent && e.originalEvent.type === "input" && !e.originalEvent.inputType) {
                    var functionToExecute = ko.utils.unwrapObservable(valueAccessor());
                    if (functionToExecute && typeof (functionToExecute) === 'function') {
                        functionToExecute(e.target.value);
                    }
                }
            });
        }
    }

This can be used with an input and datalist like this:

    <input class="form-control"
           data-bind="textInput: userInput,
                      datalistInput: function(selectedText) { console.log(selectedText); }"
           list="mydatalist">
    <datalist id="mydatalist">
        <!-- ko foreach: listOptions -->
        <option data-bind="text: $data"></option>
        <!-- /ko -->
    </datalist>
In this case, textInput will bind to anything the user enters as well as any value selected from the datalist by the user. The datalistInput will only be triggered when the user selects a value from the datalist.