https://github.com/Azure/azure-webjobs-sdk-script/wiki/Retrieving-information-about-the-currently-running-function describes a EXECUTION_CONTEXT_FUNCTIONDIRECTORY environment variable. But it's not available for F# functions. Also Microsoft.Azure.WebJobs.ExecutionContext doesn't provide a FunctionDirectory property.
This sample function confirms that the property does exist:
let Run(req: HttpRequestMessage, log: TraceWriter, context: ExecutionContext) =
log.Info context.FunctionDirectory
req.CreateResponse(HttpStatusCode.OK, "Hello")
(tested in the portal on v1 runtime)
Related
I'm just trying to figure out how to do something in .NET 5 that worked in 3.1 and before.
In 3.1, the route variable binds correctly to the Guid parameter of the same name:
[FunctionName("Function1")]
public static async Task Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "records/{clientId:Guid}")] HttpRequest req,
Guid clientId,
ILogger log)
{
return new OkObjectResult(clientId);
}
A comparable .NET 5 version of this same function fails to bind the path variable:
[Function("Function1")]
public static HttpResponseData Run([HttpTrigger(AuthorizationLevel.Function, "get", Route = "records/{clientId:Guid}")] HttpRequestData req,
Guid clientId,
FunctionContext executionContext)
{
var response = req.CreateResponse(HttpStatusCode.OK);
response.WriteString(clientId.ToString());
return response;
}
The error that is thrown is as follows:
Exception:
Microsoft.Azure.Functions.Worker.Diagnostics.Exceptions.FunctionInputConverterException:
Error converting 1 input parameters for Function 'Function1': Cannot
convert input parameter 'clientId' to type 'System.Guid' from type
'System.String'.
I can change the type of the parameter to string and then parse it into a Guid after the fact, of course, but I'd like to know if it's still possible to do it the aforementioned way.
There are two things:
Why isn't the route constraint taken into account (i.e. why does a conversion need to occur)
I found a related git issue. That doesn't seem to be fixed, though it makes me wonder how you managed to make it work with .NET Core 3.1 :)
Why isn't the input string automatically converted to a Guid
I had a look at the code to understand where the exception is raised.
The model binding is using a list of IConverter to convert between the input type and the binding type. In your case, the input type is string and the binding type is Guid, and there's no built-in converter that can do that. You can't even create your own IConverter, because it's an internal interface.
Note: here's an example of IConverter that converts a string to a byte array: StringToByteConverter
So basically, there's nothing you can do apart from your suggestion to parse the Guid yourself.
I am trying out Azure Function Apps.
The first one following the example in a tutorial with Open Weather map, stopped working after I used log.WriteLine(), which correctly threw a compiler error. I changed to log.Info() and it kept complaining about TraceWriter not containing a definition for WriteLine.
After a lengthy troubleshooting session, I created a new function, copying all the content of the broken one, and it worked immediately.
Created a new function, as before, and began making changes to the Run() method, and running this function yields:
"The resource you are looking for has been removed, had its name
changed, or is temporarily unavailable."
Bearing in mind, the function URL is based on the default key Azure generates when the function is created: https://.azurewebsites.net/api/WeatherWhereYouAre?code=my1really2RAndom3defauLT4Key5from6Azure==
Created yet another function, with no changes from the default "Hello Azure" sample, and it yields a 500 error with:
"Exception while executing function: Functions.HttpTriggerCSharp2 ->
One or more errors occurred. -> Exception binding parameter 'req' ->
Input string was not in a correct format."
This is the content of the project.json file:
{
"frameworks": {
"net46": {
"dependencies": {
"Microsoft.IdentityModel.Clients.ActiveDirectory": "3.16.0",
"Microsoft.Azure.KeyVault": "2.3.2",
"Microsoft.AspNet.WebApi.Client": "5.2.3"
}
}
}
}
And the run.csx:
using System.Net;
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
log.Info("C# HTTP trigger function processed a request.");
// parse query parameter
string name = req.GetQueryNameValuePairs()
.FirstOrDefault(q => string.Compare(q.Key, "name", true) == 0)
.Value;
// Get request body
dynamic data = await req.Content.ReadAsAsync<object>();
// Set name to query string or body data
name = name ?? data?.name;
return name == null
? req.CreateResponse(HttpStatusCode.BadRequest, "Please pass a name on the query string or in the request body")
: req.CreateResponse(HttpStatusCode.OK, "Hello " + name);
}
EDIT
In the above image, note that this is httpTriggerFSharp1, but the exception is HttpTriggerCSharp2 (which is the only one that works!)
Is there a way I can properly troubleshoot these?
For the default HttpTrigger template for C#, you could call it as follows:
Get https://brucefunapp.azurewebsites.net/api/HttpTriggerCSharp3?name=bruce&code=ItDhLMxwDYmTvMTYzVbbALtL5GEcmaL5DlzSaD4FRIuFdh17ZkY71g==
Or
Post https://brucefunapp.azurewebsites.net/api/HttpTriggerCSharp3?code=ItDhLMxwDYmTvMTYzVbbALtL5GEcmaL5DlzSaD4FRIuFdh17ZkY71g==
Content-type: application/json
{"name": "bruce"}
For more details about Azure Functions C# script, you could refer to here.
Is there a way I can properly troubleshoot these?
Per my understanding, you could leverage Precompiled functions and use Visual Studio 2017 Tools for Azure Functions for creating, local debugging, and publishing to Azure.
Following is some code extracted from my Azure Function which is being called from a Logic App:
public static async Task<object> Run(HttpRequestMessage req, TraceWriter log)
{
log.Verbose($"Function Run Called");
var jsonContent = await req.Content.ReadAsStringAsync();
log.Info($"jsonContent var assigned {jsonContent}");
dynamic data = JsonConvert.DeserializeObject(jsonContent.ToString());
log.Verbose($"data var assigned");
log.Verbose($"JsonContent: {data.FileContent}!");
bool result = true;
return req.CreateResponse(HttpStatusCode.OK, new {
result = $"Hello {result}!"
});
}
Once executed, I can see the function executed successfully without any errors, but I am unable to see what "log.Verbose" has printed. I have also tried log.Info but I don't see any output.
Any idea from where I can check the output of log.Info and log.Verbose?
If in your scenario you're not actually using our Functions portal for the invocations, then to see the logs, you can go to the "Monitor" page for your function. From the invocation log you can select individual functions and see their output under the invocation details section.
When running functions from our Functions portal, you'll see the logs in the log stream window. Note that the default TraceLevel configured for a Function app is Info. So you won't see Verbose logs. You can configure the TraceLevel in your host.json file by setting the tracing.consoleLevel property. See here for more information.
I am registering a service with ReuseScope.Request and in some cases (read below) I get the exception:
Error trying to resolve Service 'Ceco.ServiceStack.TestService.TestService' or one of its autowired dependencies (see inner exception for details).
Basically this registration:
container.RegisterAutoWiredAs<FakeAgent, IAgent>().ReusedWithin(ReuseScope.Request);
which is required for the service:
public class TestService : Service {
private readonly IAgent _agent;
public TestService(IAgent agent) {
_agent = agent;
}
public object Get(TestRequest request) {
return _agent.Process(request);
}
}
is working as expected on Windows via MS.NET with both web application and self host.
On Ubuntu 14.04 via Mono 3.2.8 web application is fine. A console application with a self host (checked all three: AppSelfHostBase, AppHostHttpListenerPoolBase and AppHostHttpListenerSmartPoolBase) is throwing the aforementioned exception. If I change the ReuseScope to None it stops complaining but it is not what I want, obviously...
I am using ServiceStack 4.0.20. The above code was working as expected with 3.9.71. The code which can be used to reproduce this is in a github repo.
Question: Is this a bug and if yes - is there a workaround or I should just stick to 3.9.71?
UPDATE1:
It seems I cannot force ServiceStack to show me the inner exception. When I add in Configure:
Config.DebugMode = true;
Config.ReturnsInnerException = true;
it just returns the following stack trace (which I think is not for the inner exception but just the general failure for not being able to resolve an instance of class implementing IAgent service):
Stack Traceat Funq.Container.ResolveImpl (string,bool) <0x0010b> at Funq.Container.ResolveNamed (string) <0x00033> at Funq.Container.Resolve () <0x00027> at (wrapper dynamic-method) object.lambda_method (System.Runtime.CompilerServices.Closure,Funq.Container) <0x00024> at ServiceStack.Host.ContainerResolveCache.CreateInstance (System.Type,bool) <0x00123> at ServiceStack.Host.ContainerResolveCache.CreateInstance (System.Type) <0x0001f> at ServiceStack.Host.ServiceController/<>c__DisplayClass11.b__f (ServiceStack.Web.IRequest,object) <0x000a1> at ServiceStack.Host.ServiceController.Execute (object,ServiceStack.Web.IRequest) <0x000af> at ServiceStack.HostContext.ExecuteService (object,ServiceStack.Web.IRequest) <0x0005f> at ServiceStack.Host.Handlers.ServiceStackHandlerBase.ExecuteService (object,ServiceStack.Web.IRequest) <0x0001b> at ServiceStack.Host.RestHandler.GetResponse (ServiceStack.Web.IRequest,object) <0x00077> at ServiceStack.Host.RestHandler.ProcessRequestAsync (ServiceStack.Web.IRequest,ServiceStack.Web.IResponse,string) <0x005e8>
An option to get RequestContext to use ThreadStatic has been added in ServiceStack v4.0.21, e.g:
RequestContext.UseThreadStatic = true;
In the Azure Service Bus namespace, there is a SubscriptionClient type, with a method to initiate a MessageSession in this manner:-
MessageSession session = subscriptionClient.AcceptMessageSession(...);
This is the synchronous version, and it returns a MessageSession. The library also provides an asynchronous version, BeginAcceptMessageSession(). This one is tripping me up, because it invokes a callback, passing in an IAsyncResult and whatever state object you wish to pass. In my case, I am passing the SubscriptionClient instance, so that I can invoke EndAcceptMessageSession() on the SubscriptionClient. BeginAcceptMessageSession() has a return type of void.
How can I access the MessageSession that is accepted via BeginAcceptMessageSession()? All I get back in the callback's result parameter is my SubscriptionClient instance, which I need in order to terminate the BeginAcceptMessageSession() via EndAcceptMessageSession().
The MessageSession reference is nowhere to be found. The documentation is no help in this regard. Searching on Google only reveals a scant 3 pages of search results, most of which is simply the online description of the method itself from MSDN. I looked in AsyncManager.Parameters and it is also empty.
Does anyone know how BeginAcceptMessageSession() is supposed to be invoked so that I can get a reference to the MessageSession thus created?
You should invoke the method like this:
Call the begin method with a method that accepts the IAsyncResult and the SubscriptionClient.
In the other method (AcceptDone in this case), call EndAcceptMessageSession with the IAsyncResult to get the MessageSession
What you see here is an standard implementation of the Asynchronous Programming Model.
private static void Do()
{
SubscriptionClient client = ...
client.BeginAcceptMessageSession(AcceptDone, client);
}
public static void AcceptDone(IAsyncResult result)
{
var subscriptionClient = result.AsyncState as SubscriptionClient;
if (subscriptionClient == null)
{
Console.WriteLine("Async Subscriber got no data.");
return;
}
var session = subscriptionClient.EndAcceptMessageSession(result);
...
subscriptionClient.Close();
}