How to share Azure function around differents solution? - c#

I am working in an app with different functions apps. Each function APP has it own VS solution and now I have to add Health Check to each Function App. Basically a function like this:
public class HealthFunction
{
private readonly HealthCheckService _healthCheckService;
public HealthFunction(HealthCheckService healthCheck)
{
_healthCheckService = healthCheck;
}
[FunctionName("health")]
public async Task<IActionResult> Health(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "health")]
HttpRequest req,
ILogger log)
{
log.Log(LogLevel.Information, "Received health request");
var status = await _healthCheckService.CheckHealthAsync();
return new OkObjectResult(Enum.GetName(typeof(HealthStatus), status.Status));
}
}
Is there some way to share this HealthFunction in something like nuget package? or something else?

Basically, function application is basing on the folder structure and existence of function.json files where function trigger and bindings are defined to create a function within a Function App.
You'd need to prepare a package that besides adding a dll, will also add the function.json to the build output.
I didn't try that, it's not simple but it seems doable.
Following links might help you:
https://learn.microsoft.com/en-us/azure/azure-functions/functions-dotnet-class-library?tabs=v2%2Ccmd#autogenerated-functionjson
https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference#function-code

Related

MediatR command inside Azure Function ServiceBusTrigger

Using some references, I have created the Azure Function App with Clean Architecture and the Project structure looks like this:
My Azure Function is of the type Service Bus Queue Trigger. Basically, I want to Call MediatR command CreateProductCommand inside this function trigger. So that, whenever there is a message pushed into Service bus Queue, I can read that and save that into SQL database using this MediatR command. CreateProductCommand has EF Core implementation.
public class SaveProductDataToDatabase
{
private readonly IMediator _mediator;
public SaveProductDataToDatabase(IMediator mediator)
{
_mediator = mediator;
}
[FunctionName("SaveProductDataToDatabase")]
public void Run([ServiceBusTrigger("product-data-dev-01", Connection = "ServiceBusConnectionString")] string myQueueItem, ILogger log)
{
log.LogInformation($"Processed message: {myQueueItem}");
}
}
I'm not sure how to use the CreateProductCommand inside this function trigger. Please help.
Adding MediatR command handler on top of a function is redundant as function is already a handler in itself and a small unit of work. A function has a single responsibility usually that responsibility is encapsulated in the function code. Unless your function has multiple responsibilities, which it shouldn’t, MediatR is unnecessary.

Azure Function Trigger Name/Connections from App Configuration

Is there now a way to set the Trigger Properties(Name/Connection) using the value from Azure App Configuration?.
I added a startup class that reads the data from Azure App Configuration but it seems the trigger set its properties earlier than that, therefore not able to bind the data that came from the app configuration.
I also found this thread about it but im not sure if there is a new update?:
https://github.com/MicrosoftDocs/azure-docs/issues/63419
https://github.com/Azure/AppConfiguration/issues/203
You can do this. The following code gets the name of the queue to monitor from an app setting, and it gets the queue message creation time in the insertionTime parameter:
public static class BindingExpressionsExample
{
[FunctionName("LogQueueMessage")]
public static void Run(
[QueueTrigger("%queueappsetting%")] string myQueueItem,
DateTimeOffset insertionTime,
ILogger log)
{
log.LogInformation($"Message content: {myQueueItem}");
log.LogInformation($"Created at: {insertionTime}");
}
}
Similarly, you can use this approach for other triggers.

Correct Way to use an async Library with ASP.NET/MVC/REST

I have an async Library for audio file processing. Furthermore I want to offer these Methods via Rest. So I made an MVC WebApi Project. The library needs some time to start, so I added a class that offers a way to init and exposes the libraries main object.
public static class MusicHandler
{
public static MusicCapture.MusicCapture MusicCapture;
public static void init()
{
MusicCapture = new MusicCapture.MusicCapture("D:\\Temp", "D:\\test", "E:\\FingerPrintDB2.ss");
MusicCapture.Start();
}
}
I start it in Application_Start()
protected void Application_Start()
{
MusicHandler.init();
}
Now when my init method contains some async calls like this:
var hashedFingerprints = command.Hash().Result;
The programm will just skip over these lines. They do not get executed for all I can tell.
Same thing happens when I call any of the objects async methods from my REST endpoints. When I run the library not from ASP.NET/MVC the code works flawlessly.
I found some comments that said that this is a problem because of deadlocks, but no advice or code how to avoid this/make this work.
Thank you in advance.
So, if I understand, you want to start something called a MusicHandler, which takes a little while to start up.
Once that has loaded, communication with your system will be via RESTful HTTP calls.
In your MusicHandler you can have a flag to state whether it has finished loading.
public static class MusicHandler
{
public static MusicCapture.MusicCapture MusicCapture;
public static bool Initialized {get;} = False;
public static void init()
{
MusicCapture = new MusicCapture.MusicCapture("D:\\Temp", "D:\\test", "E:\\FingerPrintDB2.ss");
MusicCapture.Start();
Initialized = true;
}
}
Then in your MVC Controller, you can examine this flag and return an error if initialization has not completed.
This way you don't need to worry about being async all the way to the top.
But I'm surprised you're using application_start at all... host this using kestrel and do this setup in program.cs or something, where you can be async to the top natively.
I figured my Problem out, it was twofold.
My library failing on start was a bug in the library that led to an exception which wasn't bubble up. I was able to mitigate this bug. Async calls on startup with a MVC App with .Result inside seem to actually be no problem.
My REST calls failing on async could be fixed by changing the rest controllers methods to async. I never would have thought thats possible but I found an example here: https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html
// GET api/music
public async System.Threading.Tasks.Task<string> GetAsync()
{
string result = await MusicHandler.MusicCapture.DetectAsync(5);
Console.WriteLine("Server returning: " + result);
return result;
}

How to connect from .NET .dll file to Azure using Linked Service

I want to write a code, similar to the code at the bottom of this link (https://azure.microsoft.com/en-us/blog/automating-azure-analysis-services-processing-with-azure-functions/) in Visual Studio and building a DLL file. However instead of using the connection string, i would like to use an existing Linked Service from my Azure portal.
The goal is to create a DLL that refreshes my Cube, while at the same time using an existing Linked Service which is already in my Azure Portal.
Is this possible?
Thanks.
#r "Microsoft.AnalysisServices.Tabular.DLL"
#r "Microsoft.AnalysisServices.Core.DLL"
#r "System.Configuration"
using System;
using System.Configuration;
using Microsoft.AnalysisServices.Tabular;
public static void Run(TimerInfo myTimer, TraceWriter log)
{
log.Info($"C# Timer trigger function started at: {DateTime.Now}");
try
{
Microsoft.AnalysisServices.Tabular.Server asSrv = new Microsoft.AnalysisServices.Tabular.Server();
var connStr = ConfigurationManager.ConnectionStrings["AzureASConnString"].ConnectionString; // Change this to a Linked Service connection
asSrv.Connect(connStr);
Database db = asSrv.Databases["AWInternetSales2"];
Model m = db.Model;
db.Model.RequestRefresh(RefreshType.Full); // Mark the model for refresh
//m.RequestRefresh(RefreshType.Full); // Mark the model for refresh
m.Tables["Date"].RequestRefresh(RefreshType.Full); // Mark only one table for refresh
db.Model.SaveChanges(); //commit which will execute the refresh
asSrv.Disconnect();
}
catch (Exception e)
{
log.Info($"C# Timer trigger function exception: {e.ToString()}");
}
log.Info($"C# Timer trigger function finished at: {DateTime.Now}");
}
So I guess you're using the Data Factory and you want to process your analysis services model from your pipeline. I don't see what your question actually has to do with the Data lake store.
To trigger Azure Functions from the Data Factory (v2 only), you'll have to use a web activity. It is possible to pass a Linked Service as part of your payload, as shown in the documentation. It looks like this:
{
"body": {
"myMessage": "Sample",
"linkedServices": [{
"name": "MyService1",
"properties": {
...
}
}]
}
However, there is no Analysis services linked service in the Data Factory, at least, I didn't hear of such a thing. Passing in a connectionstring from the pipeline seems like a good idea however. You could pass it as a pipeline parameter in your body of the webrequest.
Create a parameter in your pipeline
Add it to your Web Activity Payload
{
"body": {
"AzureASConnString": "#pipeline().parameters.AzureASConnString"
}
You can retrieve this value from functions like described here

C# Async MVC method returns ContentResult System.Threading.Tasks.Task`1[System.Web.Mvc.JsonResult]

I'm trying to convert some methods to async and have started off with a simple example within the controller I am modifying:
public class MyAPIController : AsyncController
{
public async Task<JsonResult> List()
{
return Json(123456, JsonRequestBehavior.AllowGet);
}
...
}
When I test the method rather than the Json result I get the string value "System.Threading.Tasks.Task`1[System.Web.Mvc.JsonResult]" which I have verified with Fiddler and by browsing.
The project has been manually upgraded to .NET45. Searches suggest that this is possibly a problem with incorrect assembly versions but a check of the project file and Process view suggests that the correct types are referenced and loaded at run time.
Does anyone have any debugging tips for this?
Thanks.
After stripping out 90% of the code to get it working and gradually adding it back in until it failed it turns out that a custom ControllerActionInvoker was being used. The fix was to change the custom invoker to inherit from AsyncControllerActionInvoker and override BeginInvokeAction instead of InvokeAction. AsyncControllerActionInvoker can handle both Async and sync methods.

Categories