ServiceStack OrmLite with multiple APIs (private and public) - servicestack

We have a .net Core 3.1 MVC web application running with ServiceStack Ormlite 5.12. Currently we have a 'public' Open API for users who wish to access data programmatically. We use the following in our AppHost:
public class AppHost : AppHostBase
{
public AppHost(IServiceProvider services, IWebHostEnvironment env)
: base("My API", typeof(MyAPIService).Assembly)
{
_appServices = services;
_env = env;
}
public override void Configure(Container container)
{
SetConfig(new HostConfig
{
...
HandlerFactoryPath = "/myapipath"
});
Plugins.Add(new OpenApiFeature
{
...
});
}
}
And in our Web.config:
<configuration>
<location path="myapipath">
<system.web>
<httpHandlers>
<add path="servicestack*" type="ServiceStack.WebHost.Endpoints.ServiceStackHttpHandlerFactory, ServiceStack" verb="*" />
</httpHandlers>
</system.web>
<!-- Required for IIS7 -->
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
<validation validateIntegratedModeConfiguration="false" />
<handlers>
<add path="servicestack*" name="ServiceStack.Factory" type="ServiceStack.WebHost.Endpoints.ServiceStackHttpHandlerFactory, ServiceStack" verb="*" preCondition="integratedMode" resourceType="Unspecified" allowPathInfo="true" />
</handlers>
</system.webServer>
</location>
</configuration>
We have MyApp.ServiceModel and MyApp.ServiceInterface projects that are accessed from the https://{baseurl}/myapipath endpoint. This all works well so far.
We wish to keep the existing OpenAPI unchanged so that users don't need to change anything when updating to a new version. But we also want to add another API for use with an angular application, either by adding a separate endpoint for a 2nd API, or by filtering out what is visible in swagger with our existing API. Is it possible to add a 2nd API plugin with a different path that is separate from the existing API?

There can be only one ServiceStack Open API Plugin registered which lists all publicly accessible APIs within an AppHost.
If you want to visually differentiate APIs you can Group related APIs with Tags:
[Tag("angular")]
public class MyRequest { ... }
Alternatively you can choose to Exclude Services from Metadata Pages with:
[ExcludeMetadata]
public class MyRequestDto { ... }

Related

NOT FOUND error on API built with .NET 6 and deployed through IIS

Program.cs
using MediatR;
using Microsoft.AspNetCore.Authentication.Negotiate;
using System.Reflection;
using WindowsProxy.Interfaces;
using WindowsProxy.Services;
var builder = WebApplication.CreateBuilder(args);
//Add services to the container.
builder.Services.AddMediatR(Assembly.GetExecutingAssembly());
builder.Services.AddControllers();
//Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
//builder.Services.AddSingleton<IAuthUserService, AuthUserService>();
//builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme).AddNegotiate();
builder.Services.AddHttpContextAccessor();
builder.Services.AddCors(options =>
{
options.AddPolicy("cors",
builder => { builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader(); });
});
//builder.Services.AddAuthorization(options =>
//{
// //By default, all incoming requests will be authorized according to the default policy.
// options.FallbackPolicy = options.DefaultPolicy;
//});
var app = builder.Build();
//Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
//app.UseAuthentication();
app.UseAuthorization();
app.UseCors("cors");
app.MapControllers();
app.Run();
web.config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<aspNetCore processPath="dotnet" arguments=".\WindowsProxy.dll" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" hostingModel="inprocess" />
<validation validateIntegratedModeConfiguration="false" />
<directoryBrowse enabled="true" />
</system.webServer>
</configuration>
<!--ProjectGuid: d0c0a55a-a8fb-4ab1-b406-55db25ed63b0-->
I have tried multiple different configs, APP pool is defined using integrated 4.0 pipeline,
agent user does have full access to file directory. App pool identity is being used by agent account. I can get this to work just fine using swagger. Was having auth issues but seem to have resolved that. It looks like I am talking to the server correctly but the error indiciates a configuration issue.
When pinging from the browser directly I get:
The resource you are looking for has been removed, had its name changed, or is temporarily unavailable.
How do I find this API on the web?

.NET Core MVC 5 Windows Authentication

I want to use Windows Authentication on my .NET Core MVC 5 web app. To allow specific domain users and an AD group.
I added a web.config in the root:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.web>
<authentication mode="Windows" />
<authorization>
<allow users="mydomain\username1, mydomain\username2" />
<deny users="?" />
</authorization>
<roleManager enabled="true" defaultProvider="AspNetWindowsTokenRoleProvider">
<providers>
<clear />
<add name="AspNetWindowsTokenRoleProvider" type="System.Web.Security.WindowsTokenRoleProvider" applicationName="/" />
</providers>
</roleManager>
</system.web>
</configuration>
I added this to startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddAuthentication(IISDefaults.AuthenticationScheme);
}
I added this in my controller
[Authorize(Roles = #"mydomain\ADgroupName")]
[Authorize(Users = #"mydomain\username1")]
public class HomeController : Controller
In project properties I disabled Anonymous auth and enabled Windows auth.
I added a project reference to Microsoft.AspNetCore.Authentication.
When all that is said and done I get the error "Type or namespace 'Users' could not be found".
What am I missing here?
the error "Type or namespace 'Users' could not be found".
From the AuthorizeAttribute Class, we can see that the Authorize attribute only have the Roles and Policy property, without the Users property, so it will show the above error.
If you want to set authorization rights for specified users, you could create a policy for the users, then, in the Controller, set the Authorize attribute as below:
[Authorize(Policy = "policyforUser")]
public class HomeController : Controller
More detail information about create policy, see the following links:
Policy-based authorization in ASP.NET Core
ASP.NET Core Authorize AD Groups through web.config
ASP.NET Core - Authorization Using Windows Authentication
Using AD groups to authorise access to pages using IIS Windows Authentication

Asp.net Core Web API - Current user & Windows Authentication

We have following technical stack in our application
AngularJS2
Asp.Net Core API
SQL Server
Now we need to store User Name for the Logged in User in table during Create/Edit for given item i.e. in Core API.
We have tried with
WindowsIdentity.GetCurrent().Name, it gives IIS APPPOOL\Asp.netCore
HttpContext.User.Identity gives null value
I get User Name with WindowsIdentity while working with Visual Studio, but with IIS, it gives value as Asp.Netcore i.e. pool name
Windows Authentication is enabled and Anonymous Authentication is disabled
Using IIS Version 6.1
Am I missing anything?
Do you have the forwardWindowsAuthToken set to true in the web.config?
<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="true"/>
I looked around and it was suggested to create Asp.Net Core WebApi application using Windows Authentication.
So when i created Asp.Net Core WebApi using Windows Authentication it worked and i got values in User.Identity objects.
So i created 2 applications i.e. one with Windows Authentication and one without, and then compared all files and found changes in following files
forwardWindowsAuthToken - true, this was tried before but issue was not solved and same was suggested by Daboul
launchSettings.json, Set windowsAuthentication: true & anonymousAuthentication: false
After doing this, I was able to values in User.Identity object.
The launchSettings.json file:
{
"iisSettings": {
"windowsAuthentication": true,
"anonymousAuthentication": false
}
}
The Web.Config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<handlers>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />
</handlers>
<aspNetCore forwardWindowsAuthToken="true" processPath="C:\Program Files\dotnet\dotnet.exe" arguments=".\YourWebsite.dll" stdoutLogEnabled="true" stdoutLogFile=".\logs\stdout" />
<security>
<authentication>
<windowsAuthentication enabled="true" />
<anonymousAuthentication enabled="false" />
</authentication>
</security>
</system.webServer>
</configuration>
On Windows Server 2012 R2/IIS 8.0, even after setting forwardWindowsAuthToken=true in web.config, User.Identity.Name was not returning the user name but IIS APPPOOL so to resolve the issue I made below change;
Go to the web application in IIS
Open Configuration Editor
Change Section to system.webServer/serverRuntime
Change authenticatedUserOverride to UseAuthenticatedUser (for me it was set to UseWorkerProcessUser)
For further details refer to below link;
https://blogs.iis.net/jaroslad/what-does-the-authenticateduseroverrideuser-do

Enabling CORS for Web API in Azure Web Apps

I have deployed a Web API project to Azure Web app. And from a angularjs app I am trying a $http.get request to the API. but it gives a CORS(cross-origin) exception though I have enabled it in my Web API startup config
app.UseCors(CorsOptions.AllowAll);
I want to Enable CORS for Azure Web App, that would solve the problem I believe
EDIT
http://nearestbuyweb.azurewebsites.net/ this is the URL of the Web app. It is trying to access http://nearestbuyapi.azurewebsites.net/api/MenuBar where the exception occurs.
I think it is not possible with Azure Web App. MSDN Question
Please help!
Note: You use CORS settings to let other websites access your site's API. Not to access other site's APIs.
Based on your comments it sounds like you're getting the CORS error when you try to make external requests from your site. That's exactly the behavior CORS is supposed to block.
For the errors to go away you would have to apply the CORS config settings on the site who's API you're trying to access.
In your case you want to make sure you're applying the config changes on the http://nearestbuyapi.azurewebsites.net site. NOT on http://nearestbuyweb.azurewebsites.net/
<system.webServer>
<httpProtocol>
<customHeaders>
<clear />
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
<add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
</customHeaders>
</httpProtocol>
</system.webServer>
I have CORS in Azure working using this:
WebApiConfig.cs:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
config.EnableCors();
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "PublicApi",
routeTemplate: "api/v1/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
Web.config:
<system.webServer>
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="OPTIONSVerbHandler" />
<remove name="TRACEVerbHandler" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers></system.webServer>
You need to remove the options handler in IIS using web.config.
http://eugeneagafonov.com/post/38312919044/iis-options-cors-aspnet-webapi-en
Sorry Guys,
The issue happens only at my corporate network. Having googled I found that corporate network can be disable CORS requests . Found this here link

Deploying a WCF Data Service/REST Service on IIS 7.5 localhost

Here are the details of my problem. I have one simple WCF Data Service (named WCFServiceAppCBS.svc) using an Entity Framework data access layer that talks to a SqlServer 2008 R2 datasource to return some entities. I just want to expose a few tables as "GET" to be later consumed by external getJSON/AJAX calls in some html files.
For development purposes, it works fine when I'm playing around with it in VS2010 using IIS Express and can consume the OData URI and return data. But, the OData service doesn't return anything when I deploy it to the localhost IIS 7.
All I get is the Atom Pub feed that lists my entities, but when I try to execute any type of iQueryable statements (i.e. http://localhost/WCFServiceAppCBS/OData.svc/officers), I get a generic "the website cannot display the page".
I'm not sure if it is having a problem authenticating or if there are other settings in my Web.Config or IIS that I'm missing.
Here's my web.config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0">
<assemblies>
<add assembly="System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
</assemblies>
</compilation>
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="true" />
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
</system.webServer>
<connectionStrings>
<add name="CBSEntities" connectionString="metadata=res://*/CBSLookup.csdl|res://*/CBSLookup.ssdl|res://*/CBSLookup.msl;provider=System.Data.SqlClient;provider connection string="data source=QCSQL2K8DEV;initial catalog=CBS;integrated security=True;multipleactiveresultsets=True;App=EntityFramework"" providerName="System.Data.EntityClient" />
</connectionStrings>
</configuration>
Here's my OData.svc.cs...
using System;
using System.Collections.Generic;
using System.Data.Services;
using System.Data.Services.Common;
using System.Linq;
using System.ServiceModel.Web;
using System.Web;
namespace WCFServiceAppCBS
{
public class OData : DataService<CBSEntities>
{
// This method is called only once to initialize service-wide policies.
public static void InitializeService(DataServiceConfiguration config)
{
// TODO: set rules to indicate which entity sets and service operations are visible, updatable, etc.
// Examples:
config.SetEntitySetAccessRule("*", EntitySetRights.AllRead);
// config.SetServiceOperationAccessRule("MyServiceOperation", ServiceOperationRights.All);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
}
}
}
Thanks for any help you can provide!

Resources