ServiceStack + Azure Cloud Service (CloudConfigurationManager) - servicestack

We've recently converted our ServiceStack application to an Azure Cloud Service.
We're finding that, internally, ServiceStack is not aware that it needs to load configuration settings (like oauth.RedirectUrl) using CloudServiceConfiguration manager instead of ConfigurationManager.
Is there a way to wire up ServiceStack appropriate for the new environment?
Thanks!

There's no AppSettings provider for Azure CloudServiceConfiguration, it should be fairly easy to create one by inheriting AppSettingsBase and overriding GetNullableString() otherwise the easiest way is to populate a Dictionary<string,string> with the configuration from Azure and load them into DictionarySettings, e.g:
AppSettings = new DictionarySettings(azureSettings);
If you want to both Web.config <appSettings/> and Azure Settings together you should use a cascading source of AppSettings in your AppHost constructor using MultiAppSettings, e.g:
AppSettings = new MultiAppSettings(
new DictionarySettings(azureSettings),
new AppSettings());

You don't need to use 'MultiAppSettings' because CloudConfigurationManager will fall back to your config appsettings section.
(appsettings only)
From my testing it seems you don't seem to need anything at all in asp.net website as web.config settings seem to get somehow overridden with azure settings. In a webjob however you will need to use the CloudConfigurationManager ...below is a suitable implementation of an servicestack AppSettings provider to wrap it.
public class AzureCloudSettings : AppSettingsBase
{
private class CloudConfigurationManagerWrapper : ISettings
{
public string Get(string key)
{
return CloudConfigurationManager.GetSetting(key, false);
}
public List<string> GetAllKeys()
{
throw new NotImplementedException("Not possible with CloudConfigurationManager");
}
}
public AzureCloudSettings() : base(new CloudConfigurationManagerWrapper()) { }
public override string GetString(string name)
{
return GetNullableString(name);
}
public override string GetNullableString(string name)
{
return base.Get(name);
}
}

Related

Azure Function as a Web API performance and pricing

We are planning to build a web application, and I was hoping someone could help us to decide whether to use Azure App Service or Azure Function for providing rest API to the client side.
Our requirements are as follows.
Authentication and authorization
CRUD on Azure SQL and Cosmos DB
Multi region
100,000,000 API calls per month
At first, we were going to build the backend using Azure App Service. But after studying pros and cons on Azure Functions, Azure Functions became more appealing to us.
So is it even a good idea to build a web application that depends on Azure Functions as a REST API provider?
Does anyone have an experience building, managing and scaling up and out Azure Functions as a REST API provider?
Is it even a good idea to build a web application that depends on Azure Functions as a REST API provider?
It seems you are planning to have REST API using Web Service or Azure Function. Your decision is perfect I would say. For Azure Function its not mandatory to have web service for that. Azure function would be best option for you. You can implement all the feature that Web API provides. So if your target is only develop API then you can start with Azure Function with no other alternative. Its outstanding actually!
Does anyone have an experience building, managing and scaling up and out Azure Functions as a REST API provider?
I am working with Azure Function for our AI Base Bot with LUIS integration. From my understanding it's a very easily maintainable, fastest response time, you can build it from anywhere. So you can undoubtedly go with Azure function.
Why Choose Azure Function:
It's stateless, need not any server to run
Full REST, can call from anywhere any Region
Can develop both Azure Portal and local Visual Studio
Cost-effective, you can pay only how much you use.
Multiple language support
Easy Authorization and Authentication functionality
No limit of calling as per your consumption plan
Do A Lot With Azure Function:
You can develop a robust API service with Azure functions. It has many outstanding features. Please check Check here
Authorization and Authentication:
You can simply integrate your authorization and authentication on your function App. Even you can implement it on each function separately or on a full application. It supports most of the popular authentication provider for example:
Azure Active Directory
Microsoft Identity
Goggle
Facebook
Twitter auth
See how can you implement authentication:
Step:1
Step:2
Rest Function Code Sample:
Here I am giving you a simple code snippet to start with: though it's on Azure Table Storage, but help you to develop azure function and CRUD concept.
Your Sample Class:
public class YourSampleClass
{
public string PartitionKey { get; set; }
public string RowKey { get; set; }
}
Table Storage Class:
public class TableStorageClass
{
public TableStorageClass()
{
}
public TableStorageClass(DynamicTableEntity entity)
{
PartitionKey = entity.PartitionKey;
RowKey = entity.RowKey;
}
public string PartitionKey { get; set; }
public string RowKey { get; set; }
}
Azure Function V2 Example:
public static class FunctionReadFromTableStorage
{
[FunctionName("FunctionReadFromTableStorage")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
//Read Request Body
var content = await new StreamReader(req.Body).ReadToEndAsync();
//Extract Request Body and Parse To Class
YourSampleClass objYourSampleClass = JsonConvert.DeserializeObject<YourSampleClass>(content);
// Validate param because PartitionKey and RowKey is required to read from Table storage In this case , so I am checking here.
dynamic validationMessage;
if (string.IsNullOrEmpty(objYourSampleClass.PartitionKey))
{
validationMessage = new OkObjectResult("PartitionKey is required!");
return (IActionResult)validationMessage;
}
if (string.IsNullOrEmpty(objYourSampleClass.RowKey))
{
validationMessage = new OkObjectResult("RowKey is required!");
return (IActionResult)validationMessage;
}
// Table Storage operation with credentials
var client = new CloudTableClient(new Uri("https://YourStorageURL.table.core.windows.net/"),
new Microsoft.WindowsAzure.Storage.Auth.StorageCredentials("YourStorageName", "xtaguZokAWbfYG4QDkBjT+YourStorageKey+T/kId/Ng+cl3TfYHtg=="));
var table = client.GetTableReference("YourTableName");
//Query filter
var query = new TableQuery()
{
FilterString = string.Format("PartitionKey eq '{0}' and RowKey eq '{1}'", objYourSampleClass.PartitionKey, objYourSampleClass.RowKey)
};
//Request for storage query with query filter
var continuationToken = new TableContinuationToken();
var storageTableQueryResults = new List<TableStorageClass>();
foreach (var entity in table.ExecuteQuerySegmentedAsync(query, continuationToken).GetAwaiter().GetResult().Results)
{
var request = new TableStorageClass(entity);
storageTableQueryResults.Add(request);
}
//As we have to return IAction Type So converting to IAction Class Using OkObjectResult We Even Can Use OkResult
var result = new OkObjectResult(storageTableQueryResults);
return (IActionResult)result;
}
}
Point To Remember:
In case of Azure Portal execution just get rid of FunctionReadFromTableStorage class
You Need following reference to execute above code
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Microsoft.WindowsAzure.Storage.Table;
using System.Collections.Generic;
Postman Request Pattern:
Function Invoke Sample:
{
"PartitionKey": "Your Param According to Table Storage Design" ,
"RowKey": "Your Param According to Table Storage Design",
"Directory": "Your Param According to Table Storage Design"
}
See The Screen Shot:
Post Man Response:
Response is subject to my own table design
[
{
"partitionKey": "Microsoft SharePoint Server",
"rowKey": "2016"
}
]
See The Screen Shot Below:
Note: For CosmosDb Integration you could check here. Azure SQL with Function take a look here.

The correct way to pass the connectionstring from Startup to any other controller

I am currently creating a Angular application with servicestack and asp.net core 2.1. I have problem with passing the connectionstring from "Startup" to the "AppHost.Configure" function (AppHost inherits from AppHostBase). What would be the correct way to do this? Should I reload the entire appsettings in AppHost, and then create a singleton in AppHost instead? Or is it some other way which I have not thought of?
I created a singleton in startup, which allows me to access in anywhere else, but not in AppHost.
If your Connection String is configured as a normal appSetting key, e.g:
"MyConnection": "Server=localhost;Database=MyDb;User Id=test;Password=test;"
Then when you pass in .NET Core's IConfiguration into your ServiceStack AppHost:
app.UseServiceStack(new AppHost
{
AppSettings = new NetCoreAppSettings(Configuration)
});
You'll be able to retrieve it as a normal App Setting, e.g:
var myConn = AppSettings.GetString("MyConnection");
If instead you configure it under the "ConnectionStrings" grouping, e.g:
"ConnectionStrings": {
"DefaultConnection": "Server=localhost;Database=MyDb;User Id=test;Password=test;"
},
Then you can either access it from the IConfiguration object, e.g:
var config = (NetCoreAppSettings) AppSettings;
var myConn = config.Configuration.GetConnectionString("DefaultConnection");
Alternatively you can also access it via the config hierarchical key notation, e.g:
var myConn = AppSettings.GetString("ConnectionStrings:DefaultConnection");

How and where to setup TelemetryClient within a netcore webApp?

I am looking to use the TrackTrace method associated with Telemetry client. An instance of TelemetryClient needs to be created in order to access this method.
A TelemetryClient can be initialised in the constructor of a controller but I was looking to see if there is a better approach and how it would be implemented?
Quote from Microsoft Docs:
Get an instance of TelemetryClient by using constructor injection, and call the required TrackXXX() method on it. We don't recommend creating new TelemetryClient instances in an ASP.NET Core application.
A singleton instance of TelemetryClient is already registered in the
DependencyInjection container, which shares TelemetryConfiguration
with rest of the telemetry. Creating a new TelemetryClient instance is
recommended only if it needs a configuration that's separate from the
rest of the telemetry.
So you can just get it injected wherever you need like this:
using Microsoft.ApplicationInsights;
public class HomeController : Controller
{
private TelemetryClient telemetry;
// Use constructor injection to get a TelemetryClient instance.
public HomeController(TelemetryClient telemetry)
{
this.telemetry = telemetry;
}
public IActionResult Index()
{
// Call the required TrackXXX method.
this.telemetry.TrackEvent("HomePageRequested");
return View();
}
but I was looking to see if there is a better approach and how it would be implemented?
To create a instance of TelemetryClient, you could just use the new operator.
TelemetryClient telemetry = new TelemetryClient();
Before using the TelemetryClient, you need to configure the Application Insight from Visual Studio.

Is it possible to set a machinekey for an Azure Worker Role

I have hosted an Owin WebAPI Server in an Azure Worker Role.
The Owin Authentication middleware seems to use the MachineKey to encrypt and generate Tokens.
This works perfectly when I have only one instance of this role, but as soon as I want to use several instances, the tokens generated by each instance are differents.
This is the same problem as a web farm, Azure automatically solves this for WebRoles using the same .net Machine Key for all instances in Web.config.
But this does not work for Worker Role instances.
Is there a trick to have Azure using the same machine key for all the intsances of a worker Role ?
Seems it would be easier than rewriting code to generate the tokens for Owin.
If your self-hosted application can reference System.Web, then you can use the same MachineKey implementaiton that the Microsoft.Owin.Host.SystemWeb does.
Put the configuration/system.web/machineKey settings in your App.config just like it is in the Web.config.
Reference reference System.Web and add the following class:
public class MachineKeyDataProtector : IDataProtector
{
private readonly string[] purposes;
public MachineKeyDataProtector(params string[] purposes)
{
this.purposes = purposes;
}
public byte[] Protect(byte[] userData)
{
return MachineKey.Protect(userData, this.purposes);
}
public byte[] Unprotect(byte[] protectedData)
{
return MachineKey.Unprotect(protectedData, this.purposes);
}
}
Then set your authentication options using that class:
var authenticationOptions = new OAuthBearerAuthenticationOptions
{
AccessTokenFormat = new TicketDataFormat(new MachineKeyDataProtector(
typeof(OAuthBearerAuthenticationMiddleware).Namespace, "Access_Token", "v1")),
AccessTokenProvider = new AuthenticationTokenProvider(),
};

ServiceStack Tenant resolution by domain

I am looking for an example implementation for resolving tenants in a multi-tenant ServiceStack API layer.
If you've got your Api host setup and you've providing an implementation of AppHostBase, you can override the Configure method like so;
public class ApiHost : AppHostBase
{
public ApiHost() : base("Service Name", typeof(ApiHost).Assembly) { }
public override void Configure(Funq.Container container)
{
//resolve your tenant here..
}
}
Now you probably want some code to resolve your tenant. Say you were doing this via subdomain, you want something like this;
string subdomain = HttpContext.Current.Request.Url.Host.Split('.')[0].ToLower();
You should probably perform some checks to ensure validity of the url too. Then just use your repository or DAL to resolve your tenant with a relevant query.
After that you need to decide how you're going to pass your tenant about to your services and such. Question for another time, probably :)

Resources