Why does Visual Studio skip some directories like Controllers, Classes, and App_Start when publishing to Azure? - asp.net-web-api

I have a classic ASP.Net forms based website where I have added s set of API hits based on the OAuthAuthorizationServerProvider class. It works great locally, now I trying to publish it to an Azure App Service. The ASP.Net portion of the website works great, no problems. But there are 2 obvious issues with the API side of the website. 1) By default the Classes, Controllers and App_Start directories do not get pushed to the App Service when publishing the website. 2) After manually publishing the missing directories the API service does not respond to the hits. POST http://test.azurewebsites.net/api/v1/token responds with a 404 (Not Found) error.
I know someone is going to ask for the contents of the App_Start files so here they are.
RouteConfig.cs
using System.Collections.Generic;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Microsoft.AspNet.FriendlyUrls;
namespace App_Start
{
public static class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
var settings = new FriendlyUrlSettings();
settings.AutoRedirectMode = RedirectMode.Permanent;
routes.EnableFriendlyUrls(settings);
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { action = "Index", id = UrlParameter.Optional }
);
}
}
}
Startup.cs
using Microsoft.Owin;
using Microsoft.Owin.Cors;
using Microsoft.Owin.Security.OAuth;
using Owin;
using System;
[assembly: OwinStartup(typeof(App_Start.Startup))]
namespace App_Start
{
public partial class Startup
{
public void Configuration(IAppBuilder App)
{
App.UseCors(CorsOptions.AllowAll);
OAuthAuthorizationServerOptions options = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/api/v1/token"),
Provider = new ApiAuthProvider(),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(5),
//AllowInsecureHttp = true
};
App.UseOAuthAuthorizationServer(options);
App.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}
}
}
WebApiConfig.cs
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
namespace App_Start
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/v1/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
}
I don't think I'm missing something in the startup for the API hits, but that is most likely the cause of my 2nd issue.
Thanks, Russ

By default the Classes, Controllers and App_Start directories do not get pushed to the App Service when publishing the website.
I have deployed the ASP.Net Web API to Azure App Service. Even Iam unable to see the Controllers, classes and Config files folders.
When we deploy the Web App, all the source files are compiled into the dll files.
Deployed Folder Structure
No need to push all the files and folders manually.
POST http://test.azurewebsites.net/api/v1/token responds with a 404 (Not Found) error.
We need to enable Routing in Configure() method inStartup.cs file.
In Startup.cs, add the below lines
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});

Related

OData Controller withing Asp.Net Core MVC application

I'm working on a project in ASP .NET Core 3.1 MVC now I want to add some API controllers to return list of objects.
For this I want to use OData Controller version 8.0.0 so I can get quarriable data to improve performance on large data tables
I'm new in ASP .NET Core and OData. can anybody explain how to configure my project's Startup file so I can run both MVC and OData controllers same time.
Kindly share some example code
Firstly, you have a MVC project, since MVC project can also expose API, so OData should also work for MVC project. Firstly, assuming you've integrate ef core and in my workaround, I followed this document to create database and data management view for a model.
Then let's add OData. Install this nuget package: Microsoft.AspNetCore.OData, modify your startup.cs file, please see the Configuration and GetEdmModel method.
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.EntityFrameworkCore;
using WebMvcNet5.Data;
using WebMvcNet5.Models;
using Microsoft.OData.ModelBuilder;
using Microsoft.AspNetCore.OData;
using Microsoft.OData.Edm;
namespace WebMvcNet5
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddControllers().AddOData(opt => opt.EnableQueryFeatures().AddRouteComponents("odata", GetEdmModel()));
services.AddDbContext<WebMvcNet5Context>(options =>
options.UseSqlServer(Configuration.GetConnectionString("WebMvcNet5Context")));
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
private static IEdmModel GetEdmModel()
{
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
//My model is Movie, and what I set "GetMovie" here means I need to create a controller named "GetMovieController"
builder.EntitySet<Movie>("GetMovie");
return builder.GetEdmModel();
}
}
}
Then this is my controller:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.OData.Query;
using WebMvcNet5.Data;
namespace WebMvcNet5.Controllers
{
[Route("odata/[Controller]")]
public class GetMovieController : Controller
{
private readonly WebMvcNet5Context _context;
public GetMovieController(WebMvcNet5Context context)
{
_context = context;
}
[EnableQuery]
public IActionResult Get()
{
return Ok(_context.Movie);
}
}
}
My test result:
I have managed to fix my issue to run Web Application which exposes OData APIs
Issue was in Startup.cs file
I'm using Asp.Net Core 3.1 and Microsoft.AspNetCore.OData v7.3.0
my Startup.cs file code is:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<AppUser, AppRole>(opt =>
{
opt.User.RequireUniqueEmail = true;
})
//.AddDefaultUI(UIFramework.Bootstrap4)
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
//add services
services.RegisterServices();
services.AddScoped<ViewRendererService>();
services.AddMvc()
.AddMvcOptions(options => options.EnableEndpointRouting = false)
.AddNewtonsoftJson(options =>
{
options.SerializerSettings.ContractResolver = new Newtonsoft.Json.Serialization.DefaultContractResolver();
})
.SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
services.AddOData();
services.AddRouting();
services.AddControllersWithViews();
services.AddRazorPages();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ApplicationDbContext dataContext)
{
if (env.EnvironmentName == "Development")
{
dataContext.Database.Migrate();
app.UseDeveloperExceptionPage();
}
else
{
app.UseDeveloperExceptionPage();
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseAuthentication();
app.UseRequestLocalization();
app.UseMvc(routes =>
{
routes.Select().Filter().OrderBy().Expand().Count().SkipToken().MaxTop(null);
routes.MapODataServiceRoute("odata", "api", GetEdmModel());
routes.MapRoute(
name: "areas",
template: "{area:exists}/{controller=Home}/{action=Index}/{id?}"
);
routes.MapRoute(
name: "Finance",
template: "{area:exists}/{controller=Account}/{action=Index}/{id?}"
);
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
private static IEdmModel GetEdmModel()
{
var builder = new ODataConventionModelBuilder();
builder.EntitySet<Product>("ProductApi");
builder.EntitySet<ProductUOM>("ProductUomApi");
ActionConfiguration action = builder.EntityType<Product>().Action("GetUOM");
action.Parameter<long>("id");
action.ReturnsCollectionFromEntitySet<Product>("Product");
return builder.GetEdmModel();
}
}
Hope this will help others

How to convert a Class Library Project to a Web API Project in Visual studio?

I have a Class Library. I want to convert this to an API project. I have created a Controller folder and a controller file. Added necessary Nuget packaged and deployed to a webroot. But the api url is giving 404 error. What am I missing?
Create Controllers folder and add a TestController.cs
public class TestController : Controller
Have a method with [HttpGet] (Optional)
[HttpGet]
public bool Index()
{
return true;
}
App_start/routeconfig.cs should be present
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new
{
controller = "{controller}",
action = "All",
id = UrlParameter.Optional
}
);
}
}
Global.asax should load routeconfig.cs
RouteConfig.RegisterRoutes(RouteTable.Routes);
Deploy dlls and folder structure to root.

Web api call works locally but not on Azure

I have same issue as per following questions and tried answer but never resolve issue
Web api interface works locally but not on Azure
Web API interface works locally but gets 404 after deployed to Azure Website
and many more similar type of...
When i tried to call api it says 404 Not Found
my WebApi.config file
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "versionApi",
routeTemplate: "api/{version}/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
API Controller
[Authorize]
[RequiresSSL]
[RoutePrefix("api/v2/Configuration")]
public class ConfigurationAPIv2Controller : ApiController
{
[Dependency]
public IConfigurationServicev2 configurationService { get; set; }
[Dependency]
public IAccountService accountService { get; set; }
#region testapi
[Route("getstring")]
[HttpGet]
public IHttpActionResult getstring()
{
return Ok("Success");
}
[Route("putstring")]
[HttpPut]
public IHttpActionResult putstring()
{
return Ok("Success");
}
#endregion
And Folder Structure is like :
i got follwowing issue for both get and Put method
404 error might caused by route issue. Since you are using route attribute for your Web API. Please make sure GlobalConfiguration.Configure(WebApiConfig.Register); is above other code.
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
And config.MapHttpAttributeRoutes(); code is above other routes configuration.
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "versionApi",
routeTemplate: "api/{version}/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
In addition, try to delete following code in your Controller to test whether it is related to the dependent injection module.
[Dependency]
public IConfigurationServicev2 configurationService { get; set; }
[Dependency]
public IAccountService accountService { get; set; }
If it also can't work for you. You could get the detail error message from web server after setting IncludeErrorDetailPolicy property in WebApiConfig class.
config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
Visual Studio does not add a default.html page to wwwroot and IIS does.
Just add default.html page to wwwroot in your project, then re-deploy to Azure.

MVC5 dependency injection issue

I have created an application using MVC5 with the onion architecture approach. The solution contains 3 projects (core, infrastructure, and UI). The UI contains both Web API controllers and MVC controllers. The issue I’m running into is dependency injection. I have installed Unity.MVC5 & Unity.WebApi. My UnityConfig.cs under App_Start Looks like this:
public static void RegisterComponents()
{
var container = new UnityContainer();
container.RegisterType<IPricingService, PricingService>();
GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container);
GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);
}
My global.asax looks like this:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
System.Web.Http.GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
UnityConfig.RegisterComponents();
}
To test out my controller, I defined my home controller like this:
private readonly IPricingService _pricingService;
public HomeController(IPricingService PricingService)
{
this._pricingService = PricingService;
}
When running home page I get
No parameterless constructor defined for this object.
Now, moving to another test scenario, I created a web api controller and looks like this:
private readonly IPricingService _pricingService;
public TestApiController(IPricingService PricingService)
{
this._pricingService = PricingService;
}
Testing the web api generates this error:
An error occurred when trying to create a controller of type 'TextApiController'. Make sure that the controller has a parameterless public constructor.","exceptionType":"System.InvalidOperationException"
Not sure what I'm missing. Please advise.
You are supposed to inject the Unity.WebApi.DependencyResolver into the WebApi configuration not in GlobalConfiguration.Configuration.DependencyResolver.
public static void Register(HttpConfiguration config)
{
var container = new UnityContainer();
container.RegisterType<IProductRepository, ProductRepository>(new HierarchicalLifetimeManager());
config.DependencyResolver = new UnityResolver(container);
// Other Web API configuration not shown.
}
You also need to implement a child container in the BeginScope method as shown in this MSDN article.

ASP.Net MVC 3: Routing URLs result in 404 when I move from local to dev server

I have a simple home and game controller set up as so:
public class HomeController : BaseController
{
public ActionResult Index()
{
return View();
}
}
public class GameController : BaseController
{
[HttpPost]
public ActionResult New(int level = 1)
{
...
}
public ActionResult FlipCard(int row, int column,Guid nonce)
{
...
}
[OutputCache(Duration=Constants.CACHE_IMAGE_EXPIRATION_SECONDS)]
public FileResult Image (Guid imageId)
{
...
}
public ActionResult Finish()
{
...
}
}
I have routing set up as such in Global.asax.cs:
public class MvcApplication : System.Web.HttpApplication
{
...
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
}
When I run the site using IIS Express; I can access http://localhost/ just fine and see the Html in my Home/Index view; as well as use actions on the game controller.
When I run the site from a virtual directory in IIS locally; I can see the same view at http://localhost/site/; and can use game controller actions here as well.
However, when I deploy to our development server in a virtual directory set up as a .Net 4 app and load up http://dev/site/; I can't see the home/index view. Instead, I just get a directory listing
of all the files in the site root sub directory. Game controller actions aren't accessible as well. Accessing any of the site's URLs results in a 404.
Google'd around for this issue; found a few solutions and tried them all; none of them seem to work.
Some notes
I do have MVC3 assemblies deployed to the local bin folder
The app pool for the site on all servers is .Net 4.0.
I built a test web form which displays the Application's root directory(Server.MapPath("~")) to confirm that the virtual directory was configured as a web app. I deployed it to http://*/site/test.aspx,
the results were as expected:
Local: c:\inetpub\wwwroot\site
Dev: e:\inetpub\wwwroot\site
I'm stumped as to what the issue is. Any ideas? Any constructive input is greatly appreciated.
Thanks,Frank
Is IIS set to hand off all requests to the .net handlers via a wildcard mapping? If not then .net will never see the request in order to process the route.
http://learn.iis.net/page.aspx/508/wildcard-script-mapping-and-iis-integrated-pipeline/

Resources