Application compatibility: Answers for common customer concerns

Application compatibility: Answers for common customer concerns

This article is contributed. See the original author and article here.

At Microsoft, we pride ourselves in providing our customers with the confidence to upgrade and update to the latest Microsoft products. Keeping up to date is crucial to minimize the risk for your customers, employees, and your business. That means helping you discover what’s possible, create a plan for success, and onboard new users and capabilities at a flexible pace.


 


The FastTrack App Assure service was launched in 2018 to fulfill Microsoft’s promise on application compatibility. While most apps will continue to work on Windows 10, Microsoft 365 Apps, Windows Virtual Desktop (WVD), Microsoft Edge, and Windows 10 on ARM64 PCs following deployment, App Assure engineers are available to help resolve any issues you might experience. This is part of the FastTrack benefit, which comes at no additional cost with eligible Microsoft 365 and Windows 10 plans of 150+ licenses.


 


Since launching, App Assure has received and evaluated nearly 750,000 applications, allowing our engineers to study and learn from customer experiences. Only a small group (approximately 0.31%) reported having any compatibility issues at all after upgrading to the latest Microsoft products, and certain questions and concerns appeared frequently. We’d like to walk through three of these commonly expressed concerns, hopefully clear up any confusion you might have, and offer some guidance based on real-world experiences over the past two years as we helped our customers resolve their application compatibility questions.


 


SUR20_ProX_Contextual_00336_RGB (1).jpg


 


Concern one: Staying current with Microsoft 365 will cause too many application compatibility issues


As our engineers have confirmed, staying current is important for avoiding application compatibility issues, while also ensuring devices remain protected with the latest in security updates. Planning ahead is a key to successful application compatibility, and we recommend that you define a readiness process to stay current with your Microsoft products and help identify potential issues—before you start your deployment. The tools outlined below will help you create your process.


 


Get started by checking out our Windows 10 deployment documentation on Docs to align to a prescriptive, process-based model for both deployment and update management that takes place across three phases: plan, prepare, and deploy. To complement this three-phase approach, there is also a step-by-step learning path to help you plan for, prepare for, and deploy updates across your organization.


 


Once you’ve completed the learning path and have begun your planning, follow these steps to help ensure application compatibility:



  1. Create an inventory of apps your company uses to make an informed decision about what to:

    1. Retire

    2. Keep and remediate (if necessary)

    3. Keep and modernize



  2. Microsoft 365 and Windows 10 E3 customers can use the Desktop Analytics tool to make an informed decision about the feature update readiness of your Windows clients

  3. Validate your enterprise apps to identify potential compatibility issues by utilizing these resources:


Readiness Toolkit for Office – Assesses application compatibility for Microsoft 365 applications.


Enterprise Site Discovery – Collects data and compatibility insights on devices running Internet Explorer to guide your Microsoft Edge deployment


Ready for Edge – A list of applications that your organization may be using that are supported on the newest version of Microsoft Edge


 


Concern two: Application code changes will always be required


Some customers described feeling reluctant to update Windows, Microsoft 365 Apps, or Microsoft Edge, as they assumed extensive discovery, triage, and mitigation efforts would be required to ensure compatibility. Specifically, changes to code were noted as a scenario our customers wished to avoid. Here, our planning comes in handy again.


 


By having a process to review the updates for Windows and Microsoft 365 Apps, potential problems (however unlikely) can be identified early—often before the update is applied in production—helping you minimize the risk of impact on your business.


 


In the rare case where code change is required to ensure that an application remains compatible, App Assure will help you resolve the issue. In most cases, there is a solution available that does not involve updating code. And if a code change is required, we will guide your team through the process. Dedicated App Assure engineers are ready to work with your developers to determine the root cause, identify any potential bugs, and make the necessary adjustments.


 


Concern three: My app won’t run on the latest Microsoft Edge browser


Most legacy and modern apps will work on Microsoft Edge, backed by Microsoft security and innovation and built on Chromium. Additionally, Microsoft Edge is included by default with the latest Windows 10 20H2 feature update. If your web apps or sites work in Internet Explorer 11, on supported versions of Google Chrome, or in any version of Microsoft Edge, those web apps and sites should work with Microsoft Edge. If it’s a legacy app and has ActiveX or Doc Mode dependencies, it will most likely work in the current version of Microsoft Edge by utilizing the IE mode feature along with the Enterprise Mode site list.


 


App Assure has helped remediate legacy apps for customers who experienced:



  • A white browser window instead of app or site content

  • Buttons missing or malfunctioning

  • Blank or inactive input fields

  • “Unsupported browser” or similar message

  • Visually misaligned content


LEARN MORE: For more Microsoft Edge deployment documentation visit here.


 


Still need help with your apps?


If you need help with application compatibility, please don’t hesitate to contact App Assure, which is available at no additional cost for eligible Microsoft 365 and Windows 10 plans of 150+ licenses. App Assure is part of the FastTrack for Microsoft 365 benefit, which includes remote guidance to help customers deploy Microsoft 365 products and capabilities. Visit aka.ms/AppAssureRequest to submit your request for assistance which will be assigned to your dedicated App Assure Manager. Learn more about App Assure compatibility assistance here. You can also watch this introductory video on App Assure.


 

Experiencing data duplication issue in Map experience for Azure Monitor for Virtual Machines

Experiencing data duplication issue in Map experience for Azure Monitor for Virtual Machines

This article is contributed. See the original author and article here.

Changes scheduled to be deployed starting from March 1, 2021, 7 AM PST for Azure Monitor for Virtual Machines (VM Insights) will impact the Map experience for a short duration (~ two hours). VM Insights will migrate to SHA256, and this deployment might cause the same process and connection to display twice in the Map UI during the rollout window. Performance and Health experiences under VM Insights will work as expected. There will be no impact on the billing as the number of records ingested does not change.


 


The changes will be deployed from March 1, 2021, to March 8, 2021, depending upon the region of the virtual machine and the Map UI might be impacted during that window.

Root-cause: The Map UI is aggregated on Process id (in VMProcess table) and Connection id (in VMConnection table) over a period of time (up to 1 hour). During the transition phase, Map UI might aggregate records based on both old and new ids and treat them as different processes or connections respectively. Here’s a snippet of the impacted Map UI:


vminsights.png


We understand that customers rely on Azure Monitor VM Insights as a critical service and apologize for any impact this incident caused.

Creating Azure Functions using .NET 5

Creating Azure Functions using .NET 5

This article is contributed. See the original author and article here.

Group

 

 

Azure Functions recently released support for .NET 5. Let’s take a look at how to upgrade our  existing Azure Functions to use it!

 

Note: This is a preview experience for .NET 5 support in Azure Functions. The Azure Functions teams notes that the “.NET 5 experience will improve in the coming weeks”.

 

Why is it more complicated than last time?

 

You might be wondering “Why can’t I just change `netcoreapp3.1` to `net5.0`?”

 

Historically, Azure Functions has always been tightly coupled with .NET, specifically Long Term Support (LTS) .NET releases. This meant that we couldn’t use a newer version of .NET until the Azure Functions team also updated their Azure Functions .NET Runtime.

 

This is the first release that moves .NET to an “out-of-process model“, allowing us to run our Azure Functions using any version of .NET!

 

Walkthrough

 

In this walkthrough, I’ll be providing snippets from the Azure Functions I use for my app GitTrends. GitTrends is an open-source app available in the iOS and Android App Stores, built in C# using Xamarin, that uses Azure Functions for its backend.

 

You can find the completed solution in the `Move-Azure-Functions-to-net5.0` branch on the GitTrends repository, here: https://github.com/brminnick/GitTrends/tree/Move-Azure-Functions-to-net5.0/GitTrends.Functions

 

1. Update .NET

 

Let’s update to .NET 5!

 

First, download the .NET 5 SDK and install it on your development machine.

 

Then, in your Functions’ CSPROJ, set the following values for `TargetFramework`, `LangVersion`, `AzureFunctionsVersion`,` OutputType` and `_FunctionsSkipCleanOutput`:

 

(Here is a completed working example)

 

 

 

 

<PropertyGroup>
	<TargetFramework>net5.0</TargetFramework>
	<LangVersion>preview</LangVersion>
	<AzureFunctionsVersion>v3</AzureFunctionsVersion>
	<OutputType>Exe</OutputType>
	<_FunctionsSkipCleanOutput>true</_FunctionsSkipCleanOutput>
</PropertyGroup>

 

 

 

 

2. Update NuGet Packages

 

Now let’s add the necessary NuGet Packages.

 

In your Functions’ CSPROJ, ensure the following `PackageReference`s have been added:

 

(Here is a completed example)

 

Note: For `Microsoft.Azure.Functions.Worker.Sdk`, add `OutputItemType=”Analyzer”`

 

 

 

<ItemGroup>
    <PackageReference Include="Microsoft.Azure.Functions.Worker" Version="1.0.0-preview3" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="1.0.0-preview3" OutputItemType="Analyzer" />
    <PackageReference Include="Microsoft.Azure.WebJobs.Extensions" Version="4.0.1" />
    <PackageReference Include="Microsoft.Azure.WebJobs.Extensions.Http" Version="3.0.12" />
    <PackageReference Include="Microsoft.Azure.WebJobs.Extensions.Storage" Version="4.0.3" />
    <PackageReference Include="Microsoft.Azure.WebJobs.Script.ExtensionsMetadataGenerator" Version="1.2.1" />
    <PackageReference Include="System.Net.NameResolution" Version="4.3.0" />
</ItemGroup>

 

 

 

3. Add Non-Windows Workaround

 

We need to include a workaround to ensure this new out-of-process worker works properly on non-Windows machines.

 

In your Functions CSPROJ, add the following `Target`:

 

(Here is a completed working example)

 

 

 

<Target Name="CopyRuntimes" AfterTargets="AfterBuild" Condition=" '$(OS)' == 'UNIX' ">
	<!-- To workaround a bug where the files aren't copied correctly for non-Windows platforms -->
	<Exec Command="rm -rf $(OutDir)bin/runtimes/* &amp;&amp; mkdir -p $(OutDir)bin/runtimes &amp;&amp; cp -R $(OutDir)runtimes/* $(OutDir)bin/runtimes/" />
</Target>

 

 

 

4. Update local.settings.json

 

To run our Functions locally, we’ll need to tell the Azure Functions Host to use the isolated dotnet runtime in `local.settings.json` by by setting `FUNCTIONS_WORKER_RUNTIME` to `dotnet-isolated`, like so:

 

(Here is a working completed example)

 

 

 

 

{
  "IsEncrypted": false,
  "Values": {
    "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated",
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "AzureWebJobsDashboard": "UseDevelopmentStorage=true"
  }
}

 

 

 

Then, in the Functions’ CSPROJ, ensure it is being copied to the output directory using `CopyToOutputDirectory` like so:

 

(Here is a working completed example)

 

 

 

<ItemGroup>
	<None Update="local.settings.json">
		<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
	</None>
</ItemGroup>

 

 

 

5. Update Initialization & Dependency Injection

 

The way we initialize Azure Functions, including Dependency Injection, for .NET 5 has improved.

 

Old Initialization & Dependency Injection (pre .NET 5.0)

 

The old way to use Dependency Injection with Azure Functions was to add the `[assembly: FunctionsStartup]` attribute and inherit from `FunctionsStartup`.

 

Here is an example of how we used to initialize Dependency Injection in Azure Functions:

 

(Here is a completed working example)

 

 

 

//Note: This is the old (pre-.NET 5) way of using Dependency Injection with Azure Functions

[assembly: FunctionsStartup(typeof(Startup))]
namespace GitTrends.Functions
{
    public class Startup : FunctionsStartup
    {
        readonly static string _storageConnectionString = Environment.GetEnvironmentVariable("AzureWebJobsStorage") ?? string.Empty;

        public override void Configure(IFunctionsHostBuilder builder)
        {
            builder.Services.AddHttpClient();();
            builder.Services.AddSingleton<BlobStorageService>();
            builder.Services.AddSingleton<CloudBlobClient>(CloudStorageAccount.Parse(_storageConnectionString).CreateCloudBlobClient());
        }
    }
}

//Note: This is the old (pre-.NET 5) way of using Dependency Injection with Azure Functions

 

 

 

New Initialization & Dependency Injection

 

The new way is to initialize Azure Functions in .NET 5 is more similar to ASP.NET. It uses to `Microsoft.Extensions.Hosting.HostBuilder`, like so:

 

(Here is a competed working example)

 

 

 

namespace GitTrends.Functions
{
    class Program
    {
        readonly static string _storageConnectionString = Environment.GetEnvironmentVariable("AzureWebJobsStorage") ?? string.Empty;

        static Task Main(string[] args)
        {
            var host = new HostBuilder()
                .ConfigureAppConfiguration(configurationBuilder =>
                {
                    configurationBuilder.AddCommandLine(args);
                })
                .ConfigureFunctionsWorker((hostBuilderContext, workerApplicationBuilder) =>
                {
                    workerApplicationBuilder.UseFunctionExecutionMiddleware();
                })
                .ConfigureServices(services =>
                {
                    services.AddHttpClient();
                    services.AddSingleton<BlobStorageService>();
                    services.AddSingleton<CloudBlobClient>(CloudStorageAccount.Parse(_storageConnectionString).CreateCloudBlobClient());
                })
                .Build();

            return host.RunAsync();
        }
    }

 

 

 

6. Update HttpTrigger Functions

 

To update an existing HttpTrigger Function, we replace the following method parameters:

  • `HttpRequest` -> `HttpRequestData`
  • `ILogger` -> `FunctionExecutionContext`

Note: `ILogger` can now be found in `FunctionExecutionContext.Logger`

 

Old HttpTrigger (pre .NET 5.0)

 

Here is an example of the old (pre .NET 5) way of creating an `HttpTrigger`:

 

(Here is a completed working example)

 

 

 

//Note: This is the old (pre-.NET 5) way of creating an HttpTrigger with Azure Functions

public static class GetGitHubClientId
{
	readonly static string _clientId = Environment.GetEnvironmentVariable("GitTrendsClientId") ?? string.Empty;

	[FunctionName(nameof(GetGitHubClientId))]
	public static IActionResult Run([HttpTrigger(AuthorizationLevel.Anonymous, "get")] HttpRequest request, ILogger log)
	{
		log.LogInformation("Retrieving Client Id");

		if (string.IsNullOrWhiteSpace(_clientId))
			return new NotFoundObjectResult("Client ID Not Found");

		return new OkObjectResult(new GetGitHubClientIdDTO(_clientId));
	}
}
//Note: This is the old (pre-.NET 5) way of creating an HttpTrigger with Azure Functions

 

 

 

New HttpTrigger

 

The new `HttpTrigger` syntax is nearly identical; only `HttpRequestData` and `FunctionExecutionContext` are now being used as its method parameters:

 

(Here is a completed working example)

 

 

 

public static class GetGitHubClientId
{
	readonly static string _clientId = Environment.GetEnvironmentVariable("GitTrendsClientId") ?? string.Empty;

	[FunctionName(nameof(GetGitHubClientId))]
	public static IActionResult Run([HttpTrigger(AuthorizationLevel.Anonymous, "get")] HttpRequestData req, FunctionExecutionContext executionContext)
	{
		var logger = executionContext.Logger;
		logger.LogInformation("Retrieving Client Id");

		if (string.IsNullOrWhiteSpace(_clientId))
			return new NotFoundObjectResult("Client ID Not Found");

		return new OkObjectResult(new GetGitHubClientIdDTO(_clientId));
	}
}

 

 

 

7. Update TimerTrigger Functions

 

To update an existing TimerTrigger Function, we must do the following:

  • Create `TimerInfo.cs`
  • `ILogger` -> `FunctionExecutionContext`

 

Create TimerInfo.cs

 

The out-of-process worker doesn’t yet include the `TimerInfo` class, but we can create it ourselves with the same properties and its values will injected at runtime:

 

(Here is a completed working example)

 

 

 

using System;
namespace GitTrends.Functions
{
    public class TimerInfo
    {
        public ScheduleStatus? ScheduleStatus { get; set; }

        /// <summary>
        /// Gets a value indicating whether this timer invocation
        /// is due to a missed schedule occurrence.
        /// </summary>
        public bool IsPastDue { get; set; }
    }

    public class ScheduleStatus
    {
        /// <summary>
        /// Gets or sets the last recorded schedule occurrence.
        /// </summary>
        public DateTime Last { get; set; }

        /// <summary>
        /// Gets or sets the expected next schedule occurrence.
        /// </summary>
        public DateTime Next { get; set; }

        /// <summary>
        /// Gets or sets the last time this record was updated. This is used to re-calculate Next
        /// with the current Schedule after a host restart.
        /// </summary>
        public DateTime LastUpdated { get; set; }
    }
}

 

 

 

Old TimerTrigger (pre .NET 5.0)

 

Here is an example of a TimerTrigger Function before updating it to .NET 5.0:

 

(Here is a working completed example)

 

 

 

//Note: This is the old (pre-.NET 5) way of creating an TimerTrigger with Azure Functions

public class SendSilentPushNotification
{
	const string _runEveryHourCron = "0 0 * * * *";
    
	readonly static string _notificationHubFullConnectionString = Environment.GetEnvironmentVariable("NotificationHubFullConnectionString") ?? string.Empty;
        
	readonly static Lazy<NotificationHubClient> _clientHolder = new(NotificationHubClient.CreateClientFromConnectionString(_notificationHubFullConnectionString, GetNotificationHubInformation.NotificationHubName));

	static NotificationHubClient Client => _clientHolder.Value;

	[FunctionName(nameof(SendSilentPushNotification))]
	public static Task Run([TimerTrigger(_runEveryHourCron)] TimerInfo myTimer, ILogger log) => Task.WhenAll(TrySendAppleSilentNotification(Client, log), TrySendFcmSilentNotification(Client, log));
}

//Note: This is the old (pre-.NET 5) way of creating an TimerTrigger with Azure Functions

 

 

 

New TimerTrigger

 

In the new TimerTrigger, in the its method parameters, we remove `ILogger`, replacing it with `FunctionExecutionContext`:

 

(Here is a working completed example)

 

 

 

public class SendSilentPushNotification
{
	const string _runEveryHourCron = "0 0 * * * *";
    
	readonly static string _notificationHubFullConnectionString = Environment.GetEnvironmentVariable("NotificationHubFullConnectionString") ?? string.Empty;
        
	readonly static Lazy<NotificationHubClient> _clientHolder = new(NotificationHubClient.CreateClientFromConnectionString(_notificationHubFullConnectionString, GetNotificationHubInformation.NotificationHubName));

	static NotificationHubClient Client => _clientHolder.Value;

	[FunctionName(nameof(SendSilentPushNotification))]
	public static Task Run([TimerTrigger(_runEveryHourCron)] TimerInfo myTimer, FunctionExecutionContext executionContext)
	{
		var logger = executionContext.Logger;

		return Task.WhenAll(TrySendAppleSilentNotification(Client, logger), TrySendFcmSilentNotification(Client, logger));
	}
}

 

 

 

8. Run .NET 5 Azure Functions Locally

 

Currently, the only way to run our .NET 5 Azure Functions locally is to use the command line.

 

Note: Visual Studio and Visual Studio for Mac have not yet been updated to run .NET 5 Azure Functions. If you try to run this code using Visual Studio, it will throw a `System.UriFormatException`: “Invalid URI: The hostname could not be parsed.”

 

1. Install Azure Functions Core Tools v3.0.3160

  • On macOS: Open the Terminal and run the following command:
    • `brew tap azure/functions; brew install azure-functions-core-tools@3`
  • On Windows: Open the Command Prompt and run the following command:
    • `npm i -g azure-functions-core-tools@3 –unsafe-perm true`

2. On the command line, navigate to the folder containing your Azure Functions CSPROJ

3. On the command line, enter the following command:

  • `func host start –verbose`

 

Note: This command is slightly different from the command you may already be familiar with, `func start`

 

9. Publish .NET 5 Azure Functions to Azure

 

Currently, the only way to publish our .NET 5 Azure Functions to Azure is to use the command line.

 

Note: Deployment to Azure is currently limited to Windows plans. Note that some optimizations are not in place in the consumption plan and you may experience longer cold starts

 

1. Install Azure Functions Core Tools v3.0.3160

  • On macOS: Open the Terminal and run the following command:
    • `brew tap azure/functions; brew install azure-functions-core-tools@3`
  • On Windows: Open the Command Prompt and run the following command:
    • `npm i -g azure-functions-core-tools@3 –unsafe-perm true`

2. On the command line, navigate to the folder containing your Azure Functions CSPROJ

3. On the command line, enter the following command:

  • `dotnet publish -c Release`

4. On the command line, navigate to the publish artifacts by entering the following command:

  • `cd ./bin/Release/net5.0/publish`

5. On the command line, publish the Function App to Azure using the following command:

  • `func azure functionapp publish <APP_NAME>`

 

Conclusion

 

The Azure Functions team is doing a ton of work to create out-of-process workers that allow us to use .NET 5.0 in Azure Functions.

 

Their work is still on going, and I highly recommend Watching & Staring the azure-functions-core-tools GitHub Repo: https://github.com/Azure/azure-functions-core-tools

 

 

Engaging Employees Using Communities and Microsoft Yammer with Dan Holme! – MidDay Café 03-01-2021

Engaging Employees Using Communities and Microsoft Yammer with Dan Holme! – MidDay Café 03-01-2021

This article is contributed. See the original author and article here.

HLS Mid-Day Café3.pngJoin the MidDay Café crew with our special guest Microsoft’s Dan Holme, Principal Program Manager, Microsoft. Dan will be talking all things communities and Yammer and show how organizations can digitally transform and create a more employee centric, engaging environment, that foster increased company loyalty while increasing productivity and job satisfaction.


Join us Monday, 03-01-2021 at 12 noon eastern for “Engaging Employees Using Communities and Microsoft Yammer with Dan Holme!”


MidDay Café 03/01/2021 Agenda:



  • Welcome and Introductions.

  • Mid-Day Café News and Events

  • Engaging Employees Using Communities and Microsoft Yammer with Dan Holme, Principal Program Manager, Microsoft.

  • Open Q&A

  • Wrap Up


For the Event:



Keep up to date with MidDay Café:



  Thanks for visiting – Michael Gannotti   LinkedIn | Twitter


Michael GannottiMichael Gannotti

Microsoft Search and More – Mid-Day Cafe 02-22-2021 Recording

Microsoft Search and More – Mid-Day Cafe 02-22-2021 Recording

This article is contributed. See the original author and article here.

middaycafe.PNG


On 02/22, at 12 noon eastern, we hosted Microsoft’s Bill Baer, Senior Technical Product Manager for Microsoft Search. Search at Microsoft has been a rapidly evolving service building upon the power of the Microsoft Graph. Properly leveraged within an organization the power of search, search driven, applications can be transformational. As Senior Technical Product Manager for Microsoft Search, Bill Baer brought us the latest in Microsoft search to help organizations unlock the potential in their Microsoft 365 data and more. Check out the recording below:


 


 


Resources:


Microsoft Search Resources from Bill Baer:



News in 2:



Upcoming Mid-Day Cafe Webcast Schedule:



  • March 1st – Dan Holme, Community/Yammer

  • March 8th – Mark Kashman, Microsoft Lists

  • March 15th – Karuana Gatimu, Teams Adoption and Governance


Keep up to date with MidDay Café:



 


Have questions/comments/suggestions/requests for the Mid-Day Café team? Post them to our Mailbag! Click here to access the Mid-Day Café Mailbag form.


 


Thanks for visiting!


Sam Brown, Microsoft Teams Technical Specialist


1572449743556.jpg