Saturday, January 9, 2021

One way to fix Failed to run web job error on Azure App Service

If you have just updated web job (see the following related articles: Upload WebJob to Azure App service with predefined schedule and How to remove Azure web job via Azure RM PowerShell) you may face with the following issue: when you will try to run updated web job you will get the error “Failed to run web job”. The problem is that error notification won’t contain any description and it will be hard to find the actual reason of this problem. In this article I will describe one of the reasons.

When web job is started it creates special lock file triggeredJob.lock in /data/jobs/triggered/{webJobName} folder of SCM site. You may check it if will connect to the site via FTP:

In the same folder there will be sub folders with timestamps which correspond to webjob runs. In these sub folders you will find output logs of each web job run – the same logs which are shown in Azure portal > App service > Web jobs > Logs. The purpose of this triggeredJob.lock file is to prevent launch of second instance of web job when previous instance didn’t finish yet. And the problem is that if during update web job was running this lock file may not be successfully deleted. As result when you will try to run updated version of web job you will get “Failed to run web job” error.

Solution will be to delete this file manually. However it is also not that straightforward. If you will try to remove it from FTP client you will get error

“The process cannot access the file because it is being used by another process”:

In order to delete it we need to stop both App Service and SCM site. Note that it is mandatory to stop both sites – if you will only stop App Service from Azure portal triggeredJob.lock will be still used by the process. Stopping of SCM site is more tricky than App Service. The process is described here: Full stopping a Web App. You need to go to Resource Explorer (azure.com) and select your App service. After that in JSON view on the right side click Edit and do 2 things:

  1. Change “state” from “Running” to “Stopped” – this is the same as if you would stop App service form Azure portal
  2. Find “scmSiteAlsoStopped” property and set it from “false” to “true” – it will stop SCM file

After that click PUT button on the top. It will stop both sites and you will be able to delete triggeredJob.lock now. Then go to Azure portal and start App service – it will start both sites. After all these steps you should be able to run web job again.

Monday, December 14, 2020

How to read Sharepoint Online sites sharing capabilities via CSOM

Sharepoint Online allows to share your sites with external users. At first administrator should enable external sharing on the tenant (organization) level (see Manage sharing settings). After that you may set external capabilities for each individual site (see Set sharing capabilities of Sharepoint site collection via client object model for how to do that). In provided example SharingCapabilities is enum which has the following values (they are quite self-descriptive so I won’t describe they here):

  • Disabled
  • ExternalUserSharingOnly
  • ExternalUserAndGuestSharing
  • ExistingExternalUserSharingOnly

In order to read sharing capabilities of existing Sharepoint Online sites via CSOM you may use the following example:

string username = ...;
string password = ...;
var adminContext = new ClientContext("https://{tenant}-admin.sharepoint.com");
var secure = new SecureString();
foreach (char c in password)
{
    secure.AppendChar(c);
}
var credentials = new SharePointOnlineCredentials(username, secure);
adminContext.Credentials = credentials;
adminContext.Load(adminContext.Site);
adminContext.ExecuteQuery();

var tenant = new Tenant(adminContext);
var properties = tenant.GetSiteProperties(0, true);
adminContext.Load(properties);
adminContext.ExecuteQuery();
foreach (SiteProperties p in properties)
{
    Console.WriteLine(p.Url + ": " + p.SharingCapability);
}

This example outputs all sites with their SharingCapability properties. If you need to get SharingCapability for single specific site add condition on site url to the last loop. Hope it will help you.

Wednesday, December 9, 2020

How to check what sensitivity label is applied to O365 group via Graph API

In order to check what sensitivity label is applied to O365 group you may go to Azure portal > Azure Active Directory > Groups > select group. Sensitivity label will be displayed in overview tab of the group:

In order to get sensitivity label applied to O365 group programmatically via Graph API you may use the following endpoint:

https://graph.microsoft.com/v1.0/groups/%7BgroupId%7D?$select=assignedLabels

It will return applied label id and display name like this:

{
    "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#groups(assignedLabels)/$entity",
    "assignedLabels": [
        {
            "labelId": "...",
            "displayName": "Private"
        }
    ]

You may test this endpoint e.g. in Graph Explorer:

Friday, December 4, 2020

How to add and remove user from site collection admins in Sharepoint Online using CSOM

Using the following code you may add user to site collection admins in Sharepoint Online via CSOM:

var adminContext = ...; // ClientContext for https://{tenant}-admin.sharepoint.com
string siteUrl = "https://{tenant}.sharepoint.com/sites/foo";
string loginName = ...; // user name which should be added to site collection admins
var tenant = new Tenant(adminContext);
tenant.SetSiteAdmin(siteUrl, loginName, true);
adminContext.ExecuteQueryRetry();

If you need to remove user from site collection admins use the following code:

var adminContext = ...; // ClientContext for https://{tenant}-admin.sharepoint.com
string siteUrl = "https://{tenant}.sharepoint.com/sites/foo";
string loginName = ...; // user name which should be added to site collection admins
var tenant = new Tenant(adminContext);
tenant.SetSiteAdmin(siteUrl, loginName, false);
adminContext.ExecuteQueryRetry();

(the difference is only that you need to pass false in tenant.SetSiteAdmin() method). Hope it will help in your work.

Tuesday, December 1, 2020

App.config vs App service configuration settings for storing app settings for Azure web jobs

As you probably know when you upload zip package with exe application to Azure App service > Web jobs (to run it as Azure web job by scheduler) – you may override app settings in App service > Configuration > Application settings section. In this case settings defined in Azure will have priority over settings defined in app.config which is deployed as part of zip package:

However it is important to note that even if you will use app settings from Azure – it is still necessary to include app.config to zip package. Otherwise if you will exclude app.config from zip package – then ConfigurationManager.AppSettings will return empty collection. So good practice is to add app.config with empty values to zip package and then manage app settings in Azure. Don’t forget to remove values from app.config – otherwise sensitive information (client secrets, passwords, keys, etc) may be accidentally leaked with zip package of web job.

Tuesday, November 24, 2020

Enable ReSharper unit tests runner with TypeMock isolator

If you use TypeMock isolator for writing unit tests (which is great library for mocking from my point of view) and ReSharper to make user experience in Visual Studio better (which is another great tool :) ) then you may face with the following problem when try to run unit tests in ReSharper test runner: tests will fail with the following error

TypeMock.TypeMockException :
*** Typemock Isolator is currently disabled. Enable using the following:

* Within Visual Studio:
    - Use Typemock Smart Runner 
    - For other runners, Choose Typemock Menu and click "Integrate with Other Runners"
 
  * To run Typemock Isolator as part of an automated process you can:
     - run tests via TMockRunner.exe command line tool
     - use 'TypeMockStart' tasks for MSBuild or NAnt
 
For more information consult the documentation (see 'Running Unit Tests in an Automated Build')
    at TypeMock.InterceptorsWrapper.VerifyInterceptorsIsLoaded()

This error will be still there even if “Integrate with other runners” option will be checked in Typemock menu:

In order to fix this problem do the following:

1. Go to TypeMock installation folder (C:\Program Files (x86)\Typemock\Isolator\x.x) and create or edit knownRunners.dat file there

2. In this file add process name of ReSharper unit tests runner on separate line: for ReSharper 2020 it will be “ReSharperTestRunner64c.exe”.
In order to know process name of the runner - run unit tests with it, find it in Process Explorer (if runner was ran from Visual Studio it will be shown under Visual Studio process tree) > right click > Properties > copy exe file name.

After that run unit tests with TypeMock in ReSharper test runner – they should work now.

Monday, November 16, 2020

Remote debugging of Azure functions in Visual Studio

When developing for Azure you should definitely take a look on Visual Studio’s Cloud Explorer (Views > Cloud Explorer) as it has features which are missing in basic Azure portal. E.g. when working with Notification hubs it allows to manage existing subscriptions for push notifications (view and delete if needed). There is one more useful feature if you develop Azure functions which I explored recently: remote debugging. It allows you to attach debugger to remote process of your Azure function app running in Azure and debug it in your Visual Studio.

In order to do that open Cloud explorer > choose subscription > App services > right click on Azure function app > Attach debugger:

If it will show error:

System.Runtime.InteropServices.COMException (0x89710023): Unable to connect to the Microsoft Visual Studio Remote Debugger named '{tenant}.azurewebsites.net'.  The Visual Studio 2017 Remote Debugger (MSVSMON.EXE) does not appear to be running on the remote computer. This may be because a firewall is preventing communication to the remote computer. Please see Help for assistance on configuring remote debugging.

ensure that port 4022 which is used by remote debugger is opened in firewall. After that you should be able to debug remote Azure functions running on Azure.