Azure Mobile App Service not picking up routes - c#

I have a project which I created via File > New > Project > Azure Mobile App
I've added routes to my HttpConfiguration in the ConfifgureMobileApp() method.
The code looks like this. Not in particular the line config.Routes.MapHttpRoute(...).
private static void ConfigureMobileApp(IAppBuilder app, ContainerBuilder builder)
{
var config = new HttpConfiguration();
builder.RegisterModule(new WebApiModule(config));
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
//For more information on Web API tracing, see http://go.microsoft.com/fwlink/?LinkId=620686
config.EnableSystemDiagnosticsTracing();
config.Filters.Add(new CultureThreadingAttribute());
config.Routes.MapHttpRoute("DefaultApi", "api/{culture}/{controller}/{id}", new { id = RouteParameter.Optional });
new MobileAppConfiguration()
.AddTablesWithEntityFramework()
.MapApiControllers()
.ApplyTo(config);
MobileAppSettingsDictionary settings = config.GetMobileAppSettingsProvider().GetMobileAppSettings();
if (string.IsNullOrEmpty(settings.HostName))
{
// This middleware is intended to be used locally for debugging. By default, HostName will
// only have a value when running in an App Service application.
app.UseAppServiceAuthentication(new AppServiceAuthenticationOptions
{
SigningKey = ConfigurationManager.AppSettings["SigningKey"],
ValidAudiences = new[] { ConfigurationManager.AppSettings["ValidAudience"] },
ValidIssuers = new[] { ConfigurationManager.AppSettings["ValidIssuer"] },
TokenHandler = config.GetAppServiceTokenHandler()
});
}
app.UseAutofacWebApi(config);
app.UseAutofacMiddleware(container);
}
But this route is not getting picked up. In my middleware, I've taken the {System.Web.Routing.RouteData} object from the OwinContext.Environment dictionary, and it contains no routes.
I am using https://learn.microsoft.com/en-us/azure/app-service-mobile/app-service-mobile-dotnet-backend-how-to-use-server-sdk, and in particular, I'm following the advice of that article by mapping the route before making the call to ApplyTo(config).
Also, my action filter CultureThreadingAttribute, which changes the locale of the thread based on the culture coming in from the route, is failing to get picked up.
I suspect that there are multiple HttpConfiguration objects running around in my app. Is there a way to fix this?

The route for your culture and the route for MobileApps APIs are conflicting with one another likely. Debugging the route handler will confirm it. Set a breakpoint and take a look at the route table as a call comes in.
There is nothing magical about the [MobileAppController] attribute - it just enforces the ZUMO-API-VERSION. You can remove the .MapApiControllers() element and use regular ASP.NET MVC routing for your API controllers. This will simplify your API route definitions.

Related

Web API slow performance

I am working on Web API project under .NET Framework 4.6 currently.
It uses bearer token authentication.
But I have noticed the issue with response time of controllers' actions. The response time is quite big even Web API is hosted on local IIS Express. Namely the logging (based on IActionFilter) shows the execution time of the controller is 20 milliseconds, meanwhile Postman shows the response time is about 3 or 4 seconds.
What can be the reason of such difference?
Two steps were taken:
to use the extension method SuppressDefaultHostAuthentication in order to avoid possible side effect from a default authentication. No improvements unfortunately.
to add the dependency injection the default implementation of interfaces which were missing initially and respective exceptions were thrown on Web API start. Namely I have added
.RegisterType<IHttpControllerSelector, DefaultHttpControllerSelector>()
.RegisterType<IHttpActionSelector, ApiControllerActionSelector>(). No improvements unfortunately.
Please find below the content of WebApiConfig.cs and Startup.cs files
WebApiConfig.cs
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
config.MapHttpAttributeRoutes();
//config.SuppressDefaultHostAuthentication();
// TODO: check the necessity to use Storages here, why not on services level
var container = new UnityContainer();
/*some dependecies mapping here*/
container.AddExtension(new Diagnostic());
config.DependencyResolver = new UnityResolver(container);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Filters.Add(new ApiAuthenticationFilter(container.Resolve<BLI.IUserSessionManagement>()));
config.Filters.Add(new ApiAuthorizationFilter(container.Resolve<BLI.IAuthorizer>(), container.Resolve<BET.IAuthLogger>()));
config.Filters.Add(new LoggingFilterAttribute(new BET.ControllerTracer()));
}
Startup.cs file
public void Configuration(IAppBuilder app)
{
//TODO : try to find better solution
BackEnd.WebAPI.Models.UnityResolver ur = (BackEnd.WebAPI.Models.UnityResolver)System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver;
Type providerType = Type.GetType("Microsoft.Owin.Security.OAuth.IOAuthAuthorizationServerProvider, Microsoft.Owin.Security.OAuth", true);
ApiOAuthAuthorizationServerProvider serverProvider = (ApiOAuthAuthorizationServerProvider)ur.GetService(providerType);
//
OAuthAuthorizationServerOptions oAuthOptions = new OAuthAuthorizationServerOptions()
{
TokenEndpointPath = new PathString("/auth"),
Provider = serverProvider,
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30),
AllowInsecureHttp = true
};
app.UseOAuthAuthorizationServer(oAuthOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}
additionally taken actions:
disable authentication and authorization filters. No improvement detected.
perform the same tests on Azure. The same situation: logging based on action filter reports high performance of contoller actions, but client receives responses with essential delay as on local IIS Express
The reason was found.
It was due to too complex controller constructor.
The revision has solved the issue

Singup/Registration page for Xamarin.Forms UWP & Android

I'm trying to create a signup/registration page for my Xamarin.Forms app. I've done a fair bit of reading on this and I've learned that authentication is a complicated process so it's best to use a service like OAuth or Azure Active Directory. I even created an account with Azure and connected my app (I think) but the documentation is sparse as far as implementing a registration page. OAuth seemed to have a pretty good tutorial on their site but it was only for Android and iOS, and my app is for Android & UWP. Is there anyone that can show how to implement a registration page in Xamarin.Forms? I don't have much of a user base yet so I'd like to use a service that's free or very cost effective, maybe like a pay per user model.
After connecting my Azure project in Visual Studio this code was auto-generated in a file called Startup.Auth.cs:
public partial class Startup
{
public void ConfigureAuth(IAppBuilder app)
{
app.UseWindowsAzureActiveDirectoryBearerAuthentication(
new WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
Tenant = ConfigurationManager.AppSettings["ida:Tenant"],
TokenValidationParameters = new TokenValidationParameters
{
ValidAudience = ConfigurationManager.AppSettings["ida:Audience"]
},
MetadataAddress = ConfigurationManager.AppSettings["ida:MetadataAddress"],
});
}
}
And this file Startup.MobileApp.cs:
public partial class Startup
{
public static void ConfigureMobileApp(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
new MobileAppConfiguration()
.UseDefaultConfiguration()
.ApplyTo(config);
// Use Entity Framework Code First to create database tables based on your DbContext
Database.SetInitializer(new MobileServiceInitializer());
MobileAppSettingsDictionary settings = config.GetMobileAppSettingsProvider().GetMobileAppSettings();
if (string.IsNullOrEmpty(settings.HostName))
{
app.UseAppServiceAuthentication(new AppServiceAuthenticationOptions
{
// This middleware is intended to be used locally for debugging. By default, HostName will
// only have a value when running in an App Service application.
SigningKey = ConfigurationManager.AppSettings["SigningKey"],
ValidAudiences = new[] { ConfigurationManager.AppSettings["ValidAudience"] },
ValidIssuers = new[] { ConfigurationManager.AppSettings["ValidIssuer"] },
TokenHandler = config.GetAppServiceTokenHandler()
});
}
app.UseWebApi(config);
}
}
But I have no idea how to work with these. What I do know is how to make a page with xaml and work with user inputs in the code behind (C#), but once I have user input like a new user name and such how do I connect to the authentication service? Any help would be appreciated, either in the form of detailed instructions or a link to a tutorial. Also I am not looking to use a 3rd party login such as login with Google or login with Facebook.

Is it possible to expose multiple Odata v4 endpoints in Asp.Net WebApi project

The title explains the requirement.
Is it possible to expose multiple endpoints in single project?
Something like:
http://localhost:8000/svc1/$metadata
http://localhost:8000/svc2/$metadata
http://localhost:8000/svc3/$metadata
Because I need to divide functionality into multiple components.
Can anyone help me?
UPDATE
Currently I'm using below code to create and expose Odata service.
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
ConfigureRoute(config);
ConfigureGlobalFilters(config);
HttpServer server = new HttpServer();
ODataBatchHandler batchHandler = new DefaultODataBatchHandler(server);
config.MapODataServiceRoute("Odata", "Odata", GenerateEdmModel(), batchHandler);
...
config.EnsureInitialized();
}
private IEdmModel GenerateEdmModel()
{
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.Namespace = "ServiceA";
builder.ContainerName = "DefaultContainer";
builder.EntitySet<Permission>("ApplicationPermissions");
return builder.GetEdmModel();
}
I would like to expose separate services for each component (under different namespaces?).
The following line should be the one you care about:
config.MapODataServiceRoute("Odata", "Odata", GenerateEdmModel(), batchHandler);
The second string parameter is the routePrefix, which means currently you're probably hitting http://yourhost.com/Odata/$metadata. If you simply create another mapping with a different prefix value (e.g. Odata2) you'd be able to make calls against http://yourhost.com/Odata/$metadata AND http://yourhost.com/Odata2/$metadata. You'll probably want to give them both a unique routeName as well though (the first string parameter), and you'll probably want to provide a different model as well so the two services will actually be different :).

WsFederation authentication in Service Fabric Owin Pipeline not working

G'day!
I haven't seen much on this because its all very new at the time of this writing. I am trying to write a service fabric application that serves a web app (html/js) after the user has been authenticated via ACS. I can easily get this to work with OWIN in a non service fabric environment, i.e. a traditional Asp Net application behind IIS. I'm trying to use token authentication with Azure Access Control.
So something to do with the fact that I am now using service fabric has changed the way OWIN works? Below is my OWIN ConfigureApp() function within my Startup.cs in my service fabric application:
public static void ConfigureApp(IAppBuilder appBuilder)
{
appBuilder.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
appBuilder.UseCookieAuthentication(new CookieAuthenticationOptions());
appBuilder.UseWsFederationAuthentication(
new WsFederationAuthenticationOptions
{
Wtrealm = _realm,
MetadataAddress = _acsXmlMetaDataUrl
});
// Configure Web API for self-host.
HttpConfiguration config = new HttpConfiguration();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
appBuilder.UseWebApi(config);
}
Notice how I inject the WsFederation middleware before the web api middleware that will eventually be used to serve my browser html/js application. Now when this launches and I do a sanity test like navigating to a REST url my content is served instantly rather than being redirected to Azure Access Control to sign in and get an auth token. In my traditional Asp Net application with the same OWIN configuration I am indeed redirected to Azure Access Control before any resources are served.
So my question is how do I inject WsFed middleware into the OWIN pipeline such that this will work in a service fabric context?
Any assistance would be much appreciated, thank you for your time!
I don't know why this code is working for MVC and not for Service Fabric. I had the same issue, but I found a way to make it work for SF.
This article gives a tutorial.
Basically, in your code, you're not telling it to authenticate. You're setting everything up but you're not starting it.
app.Map("/login", map =>
{
map.Run(async ctx =>
{
if (ctx.Authentication.User == null ||
!ctx.Authentication.User.Identity.IsAuthenticated)
{
ctx.Response.StatusCode = 401;
}
else
{
ctx.Response.Redirect("/");
}
});
});
app.Run(async ctx =>
{
var user = ctx.Authentication.User;
var response = ctx.Response;
response.ContentType = "text/html";
if (user != null && user.Identity.IsAuthenticated)
{
await response.WriteAsync(string.Format("<h2>{0}</h2>",
user.Claims.First().Issuer));
await response.WriteAsync("<dl>");
foreach (var claim in user.Claims)
{
await response.WriteAsync(string.Format(
"<dt>{0}</dt> <dd>{1}</dd>",
claim.Type,
claim.Value));
}
await response.WriteAsync("</dl>");
}
else
{
await ctx.Response.WriteAsync("<h2>anonymous</h2>");
}
});
When you're accessing a link on your website, the code in app.Run starts executing to check if you're logged in. If you're not, in this case, it will write "anonymous" on the page instead of loading your content. To authenticate, go to yourwesite/login and it will redirect you to whatever auth provider you have in the configuration.
Conclusion: add the login, logout and app.Run snippets, give it a final tweak if you have to and that should be it.

ASP.NET WebAPI Template Usage

I'm not sure if this is a question that should be asked on SO, but I can't think of a better place to ask it. What I want to know is: Does anyone out there actually use the Web API 4.5.2 Template that ships with Visual Studio. I've been writing C# Web Applications for some time now, and I feel like these templates are bloated nightmares to work with. They also seem to push developers away from understanding how things are actually working under the hood. Do you agree or disagree, and should I be using these templates if I want to call myself a .Net Web Developer?
This is ofcourse highly opinionated, but yes I agree; the default (MVC related) templates are bloated with unnecessary features and there's nothing lean and mean about them. I've used a custom template for a long time just to get around this (frustrating) problem.
Note that Visual Studio now has the option to create an empty website and gives you the option to only include WebAPI, not forcing you to include ASP.NET MVC. This produces a nice tiny project.
If you do experiment alot with WebAPI and you don't want your harddisks to be a cluster bomb full of Visual Studio projects, I can highly recommend LinqPad. With a tiny bit of code you can create a self hosting process and use it as a template. For example:
#define NONEST
void Main()
{
string baseAddress = "http://localhost:9000/";
try
{
// Start OWIN host
using (WebApp.Start<Startup>(url: baseAddress))
{
// Create HttpCient and make a request to api/values
HttpClient client = new HttpClient();
var response = client.GetAsync(baseAddress + "api/values").Result;
Console.WriteLine("response: " + response);
Console.WriteLine("result: " + response.Content.ReadAsStringAsync().Result);
}
}
finally
{
// LinqPad keeps the AppDomain running to reduce compile time.
// Force app domain unload (Displays "Query ended unexpectedly")
// You can also press shift-F5 to unload the AppDomain.
AppDomain.Unload(AppDomain.CurrentDomain);
}
}
// Define other methods and classes here
public class Startup
{
// This code configures Web API. The Startup class is specified as a type
// parameter in the WebApp.Start method.
public void Configuration(IAppBuilder appBuilder)
{
// Configure Web API for self-host.
HttpConfiguration config = new HttpConfiguration();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
appBuilder.UseWebApi(config);
}
}
public class ValuesController : ApiController
{
// GET api/values
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
}

Categories

Resources