Azure App Service - Some WebAPI methods throw OWIN Exception - azure

I have an Azure Mobile App that has some methods that generate 500 errors but does not record any exceptions in Application Insights and no exceptions are thrown inside my code. I have been able to determine that normal TableController methods work fine, but custom methods do not. Also, I can remote debug the code and watch it finish executing without any exceptions being thrown. It should also be noted that I did not have this problem when this project was a Mobile Service. Here is an example method that fails:
private readonly MobileServiceContext context; //Autofac injection
private readonly IUserHelper userHelper; //Autofac injection
[HttpGet, Route("api/Site/{id}/Users")]
public async Task<HttpResponseMessage> Users(string id)
{
var userId = await userHelper.GetUserIdAsync(User, Request);
var query = context.UserSiteMaps.Include(x => x.User).Where(map => map.SiteId == id);
var auth = query.FirstOrDefault(x => x.UserId == userId && x.IsAdmin);
if (auth != null)
{
return Request.CreateResponse(HttpStatusCode.OK, query.Select(map => map.User));
}
return Request.CreateUnauthorizedResponse();
}
The deepest error log that I have been able to obtain is the detailed error page from IIS:
Module __DynamicModule_Microsoft.Owin.Host.SystemWeb.OwinHttpModule, Microsoft.Owin.Host.SystemWeb, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35_9de2321b-e781-4017-8ff3-4acd1e48b129
Notification PreExecuteRequestHandler
Handler ExtensionlessUrlHandler-Integrated-4.0
Error Code
0x00000000
I haven't been able to generate a more detailed error message and I have no idea what Owin is upset about here since other method return requests just fine. Am I doing something I shouldn't?
Any help would be greatly appreciated!
Update : Here is the full error message that I have been able to get.
I have also been able to narrow the cause down a bit. If I replace the query.Select(map => map.User) object in the response with a simple string, it returns that string without complaint. However, if I stringify the response myself and pass that in, I get 500s again. Could it be some serializer setting problem?

The best way to track down the issue is to turn on exception stack traces for you app and to turn on logging on your Mobile App backend.
See Server Side Logging in the Mobile Apps wiki and Enable diagnostics logging for web apps in Azure App Service. You can also remote debug your service to see the exact error, see Remote debugging .NET server SDK.

Related

Microsoft Graph returning null account even after passing a valid account ID

I am encountering a weird issue with Microsoft Graph on an integration that was built a few years back.
This issue started happening a few months back. After I sync a Microsoft Account and provide email and calendar read/write access, everything works fine for some time. I am able to retrieve emails and calendar events. However, after some time, I notice that when a call is made to GetAccountAsync with a valid AccountID, null is returned. This is causing AcquireTokenSilent to fail with the following error:
Error Code: user_null
Error Message: No account or login hint was passed to the AcquireTokenSilent call.
I have also noticed that this happens under the following scenarios:
When the WebJob (console app) is run every 15 minutes, I encounter this issue
To narrow down the root cause, I have deleted the WebJob to see if the issue occurs on the web app. It looks like the issue starts to occur after an hour or so even without the web job running.
I have upgraded to the latest version of MSAL and implemented 4.46.1.0 version of Microsoft.Identity.Client. I am using .NET Framework 4.8 and this is a .NET MVC 5 app.
Here's my code:
public async Task<string> GetAccessTokenAsync()
{
string accessToken;
UserExternalApp.Scope = string.IsNullOrWhiteSpace(UserExternalApp.Scope) ? "" : UserExternalApp.Scope;
// Load the app config from web.config
var microsoftScopes = UserExternalApp.Scope.Replace(' ', ',').SplitAndTrim(new char[] { ',' }).ToList();
var accountID = UserExternalApp.ExternalUserAccountID;
var app = ConfidentialClientApplicationBuilder.Create(ClientID)
.WithRedirectUri(DefaultRedirectUrl) // https:\//mywebsite.com
.WithClientSecret(Secret)
.Build();
app.AddDistributedTokenCache(services =>
{
services.AddDistributedSqlServerCache(options =>
{
options.ConnectionString = System.Configuration.ConfigurationManager.ConnectionStrings["Connection"].ConnectionString;
options.SchemaName = "dbo";
options.TableName = "TokenCache";
options.DefaultSlidingExpiration = TimeSpan.FromMinutes(90);
});
});
try
{
var account = await app.GetAccountAsync(accountID);
var query = app.AcquireTokenSilent(microsoftScopes, account); // This is where the error is thrown
var acquireTokenSilent = await query.ExecuteAsync();
accessToken = acquireTokenSilent.AccessToken;
}
catch
{
// This is the error thrown:
// Exception Type: MsalUiRequiredException
// Error code: user_null
// Exception Details: No account or login hint was passed to the AcquireTokenSilent call.
throw;
}
return accessToken;
}
I know the token is persisted on my SQL Server:
I think the MSAL uses an in memory token cache by default, Once the client logins, authentication information will be stored in cookie(if cookie has not been disabled). Even your web application restarts, the client will keep logged in.
To solve this, you can use custom Token cache serialization in MSAL.NET:https://learn.microsoft.com/en-us/azure/active-directory/develop/msal-net-token-cache-serialization?tabs=aspnet.
Hope this helps.
I would like to share the resolution to this problem in case if it helps someone in the future. I feel that this is a Microsoft Bug that was introduced during one of their many upgrade process as this code went from working to broken without any change from our end. Here are the steps I took:
While exchanging the code for a token after user authentication, I retrieved and saved Account.HomeAccountId.Identifier, Account.HomeAccountId.ObjectId and TenantId for the account.
I implemented my own version of IAccount.
Instead of calling await app.GetAccountAsync(accountID), I used my implementation of IAccountand initialized it with the data I saved in Step 1.
I used this account to call app.AcquireTokenSilent(microsoftScopes, account).
And that's it! No error was thrown once this was done!

Azure Function App: Authentication Breaks Development Portal

I've added Azure Active Directory Authentication to my function app, but as soon as I set "Action to take when request is not authenticated" to "Login with Azure Active Directory", the development interface for the function app yields this message:
Error:
We are unable to reach your function app. Your app could be having a temporary issue or may be failing to start. You can check logs or try again in a couple of minutes.
Session Id: 23a5880ec94743f5a9d3ac705515b294
Timestamp: 2016-11-16T08:36:54.242Z
Presumably adding the authentication requirement breaks access to the function app in some fashion... though I am able to make changes in the code editor, and they do take effect, I no longer see updates in the log panel: no compilation output messages, for example.
Does anyone know a work-around for this?
So far, I've tried just leaving the auth option to "Allow anonymous requests (no action)" and using this following code:
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
log.Info("C# HTTP trigger function processed a request.");
var user = "Anonymous";
var claimsPrincipal = Thread.CurrentPrincipal as ClaimsPrincipal;
if (claimsPrincipal != null && claimsPrincipal.Identity.IsAuthenticated)
{
user = claimsPrincipal.Identity.Name;
log.Info($"Hello {user}");
}
return req.CreateResponse(HttpStatusCode.OK, "Hello " + user);
}
However, this (rightly) doesn't redirect to the authentication provider... I would prefer to have the app take care of all that gunge for me, but if doing so means I can't see compilation messages / log messages, it makes it pretty hard to see what's going on.
Nathan,
Unfortunately, this is a limitation at the moment and we're tracking it here: https://github.com/projectkudu/AzureFunctionsPortal/issues/794
Your approach, to allow anonymous and validate in the function is what we recommend at the moment. To extend your workaround, you can add the following code to initiate a login redirect when you detect an anonymous user (the code below assumes you are using AAD).
else
{
log.Info("Received an anonymous request! Redirecting...");
var res = req.CreateResponse(HttpStatusCode.Redirect);
res.Headers.Location = new Uri(req.RequestUri, $"/.auth/login/aad?post_login_redirect_uri={req.RequestUri.AbsolutePath}&token_mode=session");
return res;
}
We understand that isn't ideal and appreciate your patience while we work to improve this.
Thanks!

What kind of exceptions will be caught by Microsoft.Owin.Diagnostics.ErrorPageExtensions.UserErrorPage

I got the demo code from http://blogs.msdn.com/b/webdev/archive/2013/11/22/debugging-owin-app-or-framework.aspx , and it shows a sexy error page.
app.UseErrorPage(new ErrorPageOptions()
{
//Shows the OWIN environment dictionary keys and values. This detail is enabled by default if you are running your app from VS unless disabled in code.
ShowEnvironment = true,
//Hides cookie details
ShowCookies = false,
//Shows the lines of code throwing this exception. This detail is enabled by default if you are running your app from VS unless disabled in code.
ShowSourceCode = true,
});
app.Run(async context =>
{
throw new Exception("UseErrorPage() demo");
await context.Response.WriteAsync("Error page demo");
});
}
However, if I throw a exception in a Controller action, the error page will not shown, and I still see the YSOD.
So I want to know what exceptions will be caught by UseErrorPage? Do I need additional configurations to make it works?
And by Controller action you mean MVC? MVC does not run directly on OWIN, so Asp.Net sees the exception first and shows you the YSOD. The Katana ErrorPage can only show you exceptions that happen in the OWIN pipeline.

SignalR - Can't create url for HubConnection

I started to work with SignalR on Visual Studio 2012, so far I got the basic hang of it, I guided myself through this example (You can browse the code in the page). I decided I wanted to add a REST service to said example, so I added a basic service to it and it worked.
The next step I wanted to take was to add a communication between the service and SignalR, so according to what the example showed to me, I only needed to create a HubConnection through the url in my project (in this case, the example uses the url http:localhost:4200). You can check the WorkerRoleHubConfiguration class, it has a method that has the next line:
return RoleEnvironment.GetConfigurationSettingValue("GUI_URL");
Where GUI_URL is http:localhost:4200.
In my service class then I just added a method with the following:
var url = RoleEnvironment.GetConfigurationSettingValue("http://localhost:4200");
try
{
HubConnection _connection = new HubConnection(url);
IHubProxy _hub = _connection.CreateProxy("SiteMonitR");
_hub.Invoke("displayResult");
}
catch (Exception ex)
{
error = ex.ToString();
}
But that throws an exception, this one.
I don't undertand why I can get the url in the same way the example does, as I'm doing everything as it's done on the Server class.
The goal I'm trying to achieve is that when an endpoint is accesed and something changes in my system, SignalR notifies to the clients connected to it.
I hope anyone can help me understand what's wrong with my work.
EDIT
I'm adding my ServiceConfiguration.Local.cscfg, my ServiceConfiguration.Cloud.cscfg and ServiceDefinition.csdef files as reference here, I think the problem should be around there but to be honest I got no idea as to why this isn't working.
EDIT 2
I'm getting the following exception at this line var url = RoleEnvironment.GetConfigurationSettingValue("http://localhost:4200");
The exception is:
SEHExcetion occurred. External component has thrown an exception.
The URL is for a GUI - it has to be a web interface for signalr to negotiate the hub connection. In the example, the hub (server) sends updates to connections coming from the configured URL - again a web interface (html page).
The logic to communicate needs to reside in the Server class and be called from the worker role. For example, after making a call to your service in the worker role, then call server.DoSomething("message") to invoke a message to the server. THat code would look something like:
public Class Server
{ ...
public void DoSomething(string message)
{
_hub.Invoke("doSomething", message);
}
...
}
Then in Server.Run() add:
// whenever a DoSomething is called
_hub.On<string>("doSomething", (message) => _hub.Invoke("doSomething", message));
And in SiteMonitRNotificationHub
public class SiteMonitRNotificationHub : Hub
{
...
public void DoSomething(string address)
{
Clients.doingSomething(address);
}
...
}
Finally in the controller script in the web gui:
c.siteMonitorHub
...
.on('doingSomething', function (message) {
c.doSomething(message);
})
and...
this.doSomething= function (message) {
// do something in your web page with message
};

Logging Servicestack Bad Requests

Is there a way to log the validation results which get populated in the ResponseStatus when you have the ValidationFeature plugin enabled?
From what i can understand, any requests coming in get validated and if the validation passes then it goes to the service. Using request filters i can log the requests coming in however using the response filters i can only log valid requests.
I trying to log all responses especially HttpStatus 400 (Bad request) which is returned as a result of a validation error.
I have also tried to play a bit with the RequestLog plugin but from what i understood what gets logged are only valid request (i.e requests that went to the service).
I hope you understand what i am trying to say.
Look to see how 7digital have customized ServiceStack's Validation Feature to support logging.
Related Features
The new API supports the concept of a ServiceRunner you can override to add your own event and exception hooks you can read about in the wiki.
There is also the built-in Request Logger that lets you expect details of the more recently processed requests.
Create an issue on the GitHub project if you want to see logging in the validation feature.
A quick way to log errors from the ValidationFeature plugin is simply thus:
public override void Configure(Container container)
{
...etc...
Plugins.Add(new RequestLogsFeature() { etc });
Plugins.Add(new ValidationFeature()
{
ErrorResponseFilter = MyValidationError
});
...etc...
}
public object MyValidationError(ValidationResult validationResult, object errorDto)
{
Container.Resolve<IRequestLogger>().Log(null, null, errorDto, TimeSpan.Zero);
return errorDto;
}
However, in my case, I realized that logging validation errors in the service itself is not the proper place; I instead log these errors in the applications that consume the service.

Resources