Thursday, November 25, 2021

Sharepoint Online remote event receivers attached with Add-PnPEventReceiver depend on used authentication method

Today I have faced with another strange problem related with SPO remote event receivers (wrote about another strange problem here: Strange problem with remote event receivers not firing in Sharepoint Online sites which urls/titles ends with digits). I attach remote event receiver using Add-PnPEventReceiver cmdlet like that:

Connect-PnPOnline -Url ...
$list = Get-PnPList "MyList"
Add-PnPEventReceiver -List $list.Id -Name TestEventReceiver -Url ... -EventReceiverType ItemUpdated -Synchronization Synchronous

In most cases RER is attached without any errors. But the question will it be fired after that. As it turned out it depends how exactly you connect to the parent SPO site with Connect-PnPOnline: remote event receiver is attached successfully in all cases (you may see them in SPO client browser) but in some cases they won't be triggered. In fact I found that they are triggered only if you connect with "UseWebLogin" parameter, while in all other cases they are not. In the below table I summarized all methods which I tried:

# Method Is RER fired?
1
Connect-PnPOnline -Url ... -ClientId {clientId}-Interactive
No
2 Connect-PnPOnline -Url ... -ClientId {clientId}     No
3 Connect-PnPOnline -Url ...
No
4 Connect-PnPOnline -Url ... -UseWebLogin
Yes


Monday, November 22, 2021

Strange problem with remote event receivers not firing in Sharepoint Online sites which urls/titles ends with digits

Some time ago I wrote about Sharepoint Online remote event receivers (RERs) and how to use Azure functions with them: Use Azure function as remote event receiver for Sharepoint Online list and debug it locally with ngrok. When I tested RERs on another SPO sites I've faced with very strange problem: on those sites which urls/titles end with digits remote event receivers were not fired. E.g. I often create modern Team/Communication sites with datetime stamp at the end:

https://{tenant}.sharepoint.com/sites/{Prefix}{yyyyMMddHHmm}
e.g.
https://{tenant}.sharepoint.com/sites/Test202111221800

I noticed that on such sites RER was not called because of some reason. I've used the same PowerShell script for attaching RER to SPO site as described in above article and the same Azure function app running locally with the same ports and ngrok tunneling.

After I created site without digits at the end (https://{tenant}.sharepoint.com/sites/test) - RER started to work (without restarting AF or ngrok - i.e. I used the same running instances of AF/ngrok for all tests which ran all the time). Didn't find any explanation of this problem so far. If you faced with this issue and know the reason please share it.

Friday, November 12, 2021

Fix Azure functions error "Repository has more than 10 non-decryptable secrets backups (host)"

Today I've faced with strange issue: after update of Azure function app which was made from Visual Studio Azure functions stopped working. The following error was shown in the logs:

Repository has more than 10 non-decryptable secrets backups (host)

In order to fix this error perform the following steps:

1. In Azure portal go to Azure function app > Deployment center > FTPS credentials and copy credentials for connecting to function app by FTP:


2. Then connect to Azure function app by FTP e.g. using WinSCP client.

3. Go to /data/functions/secrets folder and remove all files which have name in the following form:
*.snapshot.{timestamp}.json

4. After that go to Azure portal > Function app and restart it. It should be started now.

Wednesday, November 3, 2021

How to configure number of retries for processing failed Azure queue message before it will be moved to poison queue

In my previous post I showed how to configure Azure web job host to set number of queue messages which may be processed simultaneously (in parallel): How to set limit on simultaneously processed queue messages with continuous Azure web job. In this post I will show how to configure web job host for processing failed messages.

As it was mentioned in previous post when message is added to Azure queue runtime will call method with 1st parameter decorated with [QueueTrigger] attribute. If there was unhandled exception this message will be marked as failed. Azure runtime will try to process this message again - by default there are maximum 5 retries for failed messages.

If we don't need to make 5 attempts (e.g. if our logic requires only 1 attempt) we may change this behavior using the following code:

public virtual void RunContinuous()
{
    var storageConn = ConfigurationManager.ConnectionStrings["AzureWebJobsDashboard"].ConnectionString;
    var config = new JobHostConfiguration();
    
    config.Queues.MaxDequeueCount = 1;
    
    var host = new JobHost(config);
    host.RunAndBlock();
}
 
public void ProcessQueueMessage([QueueTrigger("orders")]string message, TextWriter log)
{
    log.WriteLine("New message has arrived from queue");
    ...
}

I.e. we set config.Queues.MaxDequeueCount to 1. In this case failed message will be moved to poison queue immediately and web job won't try to process it again.

Tuesday, November 2, 2021

How to set limit on simultaneously processed queue messages with continuous Azure web job

With continuous Azure web job we may create web job host which will listen to specified Azure storage queue. When new message will be added to queue Azure will trigger handler method found in assembly of continuous web job (public method which has parameter with [QueueTrigger] attribute):

public virtual void RunContinuous()
{
    var storageConn = ConfigurationManager.ConnectionStrings["AzureWebJobsDashboard"].ConnectionString;
    var config = new JobHostConfiguration();
    config.StorageConnectionString = storageConn;
    var host = new JobHost(config);
    host.RunAndBlock();
}

public void ProcessQueueMessage([QueueTrigger("orders")]string message, TextWriter log)
{
    log.WriteLine("New message has arrived from queue");
	...
}

If several messages were added simultaneously Azure will trigger several instances of handler method in parallel. Number of messages which can be processed in parallel can be configured via JobHostConfiguration.Queues.BatchSize property. By default it is set to 16 i.e. by default 16 messages can be processed simultaneously in one batch:

 

If we want e.g. configure continuous web job so it will process only 1 message at time we can set BatchSize to 1:

public virtual void RunContinuous()
{
    var storageConn = ConfigurationManager.ConnectionStrings["AzureWebJobsDashboard"].ConnectionString;
    var config = new JobHostConfiguration();
    config.StorageConnectionString = storageConn;
	
    // set batch size to 1
    config.Queues.BatchSize = 1;
	
    var host = new JobHost(config);
    host.RunAndBlock();
}

public void ProcessQueueMessage([QueueTrigger("orders")]string message, TextWriter log)
{
    log.WriteLine("New message has arrived from queue");
	...
}

Using the same approach we can increase BatchSize from default 16 to bigger value. However as you may notice from above screenshot MaxBatchSize is set to 32 to you may increase BatchSize only up to 32.

Monday, October 18, 2021

Obfuscar + NVelocity + anonymous types = issue

Some time ago I faced with interesting issue related with Obfuscar and anonymous types used with NVelocity template engine. If you use NVelocity for populating templates then your code may look like this:

string Merge(string templateText, params Tuple<string, object>[] args)
{
    var context = new VelocityContext();
    foreach (var t in args)
    {
        context.Put(t.Item1, t.Item2);
    }

    var velocity = new VelocityEngine();
    var props = new ExtendedProperties();
    velocity.Init(props);
    using (var sw = new StringWriter())
    {
        velocity.Evaluate(context, sw, "", templateText);
        sw.Flush();
        return sw.ToString();
    }
}

Here we pass templateText itself and tuple(s) of (key, value) pairs where key is string name of parameter used inside template (like $p) and value is object which has to be used for expanding this parameter to the real string value in resulting text (e.g. if you have "$p.Foo" inside template then pass object which has "Foo" string property set to "bar" value - then "$p.Foo" in template will be replaced by "bar").

For objects passed as parameters into this method anonymous types can be used - it is very convenient:

string text = Merge("My object $p.Foo", Tuple.Create("p", new { Foo = "bar" }));

If you will run this code as is it will return "My object foo" which is correct. But if you will try to obfuscate your code with Obfuscar then you will get unexpected result: instead of expanded template you will get original template text "My object $p.Foo" i.e. template won't be expanded to string.

The reason of this problem is that Obfuscar by default removes properties of anonymous types - there are issues about that: Anonymous class obfuscation removes all the properties or Anonymous Types. In order to solve the problem you need to instruct Obfuscar to not obfuscate anonymous types:

<Module file="MyAssembly.dll">
  <SkipType name="*AnonymousType*" skipProperties="true" skipMethods="true" skipFields="true" skipEvents="true" skipStringHiding="true" />
</Module>

After that anonymous types won't be changed and NVelocity templates will be populated to string correctly.

Friday, October 15, 2021

Convert self-signed SSL certificate's private key from .pfx to .key and .crt

Some time ago I wrote a post how to use self-signed SSL certificate in Azure App service: Use self-signed SSL certificate for web API hosted in Azure App service. In this article we generated self-signed certificate, exported private key to pfx file and used it in Azure. But what it you will use another hosting provider which require private key in .key format and SSL certificate itself in .crt file? Good news is that it is possible to create .key/.crt files from .pfx and in this article I will show how to do that.

We will need openssl.exe tool which will make actual work. If you will try to Google it there will be plenty of 3rt party sites where you may download that. The problem however is that there is no guarantee that these are safe download links (i.e. that there won't be malwares and viruses). Safer option is to use openssl.exe which is shipped with git client for Windows: I found my in the following location:

C:\Program Files\Git\usr\bin\openssl.exe

With this tool in order to export SSL certificate from .pfx to .crt we may use the following command:

openssl pkcs12 -in myCert.pfx -clcerts -nokeys -out myCert.crt

and in order to export private key to .key format from .pfx the following:

openssl pkcs12 -in myCert.pfx -nocerts -out myCert-encrypted.key

Here you will need to specify pfx password and also provide so called PEM pass phrase which will proteck .key file. I.e. private key in .key format will be still encrypted. If you will need it in unencrypted format (ensure that it will be stored in safe location in this case) use the following command:

openssl rsa -in myCert-encrypted.key -out myCert-decrypted.key

After that you will be able to use self-signed SSL certificate in .key/.crt format.

If you need certificate in.pem format you may get it by concatenating myCert-decrypted.key and myCert.crt files - resulting .pem file should have the following parts (first is copied from myCert-decrypted.key and second from myCert.crt):

-----BEGIN RSA PRIVATE KEY-----
...
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----

So if your hosting provider requires .pem file you will be able to use it there.