Azure Mobile Services Sync Context: Adding custom parameters - c#

I am using Azure Mobile Services to provide data to a Windows Universal app and Azure API Management as a proxy for API usage and analytics purposes. This is working great.
Now I was asked to provide offline functionality to the application so I started using Azure Mobile Services Synchronization Context in order to implement this using SQLite as the local store.
Azure API Management requires me to send my subscription key as part of my query string. I have been doing this using the 'parameters' dictionary provided by the IMobileServiceTable.InsertAsync method and this was working fine as well.
Now the offline implementation requires me to use IMobileServiceSyncTable.InsertAsync method instead, which doesn't provide an overload with the 'parameters' dictionary. The MobileServiceSyncContextExtensions.PushAsync method does not seem to provide a way to add custom parameters to the query string either.
Does anyone know of a way to include custom parameters when using the Mobile Services Synchronization Context in order to send the subscription key of the Azure API Management service?

I've found the way to do this.
I implemented the following HTTP Message Handler:
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
class AzureApiManagementHandler : DelegatingHandler
{
string _subscriptionKey;
public AzureApiManagementHandler(string subscriptionKey)
{
_subscriptionKey = subscriptionKey;
}
protected override System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
{
var baseUri = new UriBuilder(request.RequestUri);
string queryToAppend = string.Format("subscription-key={0}", _subscriptionKey);
if (baseUri.Query != null && baseUri.Query.Length > 1)
baseUri.Query = baseUri.Query.Substring(1) + "&" + queryToAppend;
else
baseUri.Query = queryToAppend;
request.RequestUri = baseUri.Uri;
return base.SendAsync(request, cancellationToken);
}
}
And then I passed it to the Mobile Services client in the constructor:
public static MobileServiceClient MobileService = new MobileServiceClient(
"https://yoursubdomainhere.azure-api.net",
"yourapikeyhere",
new AzureApiManagementHandler("yoursubscriptionkeyhere")
);
I hope this is useful for anyone facing the same problem.

Related

Azure Function c# - Retrieve list of subscription's WebApp

We want to create an azure function in c# that retrieve the list of azure web app contained in the subscription (basically we want to call dynamically, for each webapp, the same API endpoint changing the subdomain of the api).
It's possible with c# retrieve the list of the web app contained in the same azure function subscriptions?
Usually we connect to the master database, we query the sys.databases to collect the dbname and understand the webapp names. But we are searching for a smartest way.
If you're in C# land, I'd look at using the ArmClient class to retrieve what you're looking for.
Install these (I've got a few others installed but start with that and see how you go, there may be a couple of others needed) Nuget packages ...
Azure.Identity;
Azure.ResourceManager;
Azure.ResourceManager.AppService
... and from there, using the DefaultCredential approach (if you've never used it, read up on it here -> https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/identity/Azure.Identity/README.md) you can query your subscriptions webApps ...
using Azure.Identity;
using Azure.ResourceManager;
using Azure.ResourceManager.AppService;
using System;
using System.Threading.Tasks;
namespace AzureManagement
{
internal class Program
{
static void Main(string[] args)
{
GetAzureResources().Wait();
}
static async Task GetAzureResources()
{
var credential = new DefaultAzureCredential();
var armClient = new ArmClient(credential);
var subscription = await armClient.GetDefaultSubscriptionAsync();
var webSitesEnumerator = subscription.GetWebSitesAsync().GetAsyncEnumerator();
try
{
while (await webSitesEnumerator.MoveNextAsync())
{
var webSite = webSitesEnumerator.Current;
Console.WriteLine($"Web App Name ........ {webSite.Data.Name}");
Console.WriteLine($"Default Host Name ... {webSite.Data.DefaultHostName}\n");
}
}
finally
{
await webSitesEnumerator.DisposeAsync();
}
Console.ReadLine();
}
}
}
The above is obviously not a function app but the core code will still work for you and can be ported as need be.
Note: I could be telling you how to suck eggs, but, once deployed to Azure, you'll need to do the necessary work to ensure that the function app has the required access to retrieve all of the resource information you're looking for.
If you're unfamiliar with that, read up on the managed identity concept. It's very easy to setup -> https://learn.microsoft.com/en-us/azure/app-service/overview-managed-identity
Yes, one easy way is to use HttpClient and send a request to Azure Rest API:
GET https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.Web/sites?api-version=2022-03-01
https://learn.microsoft.com/en-us/rest/api/appservice/web-apps/list
PS: you first need to acquire an authentication token.
https://www.youtube.com/watch?v=6b1J03fDnOg&t=329s

dotnet core Google Cloud Function with Firebase Admin SDK

I have a Flutter client app that authorises the user using Google Provider. I want to use the dotnet core C# Google Cloud function to read the authorisation token and read the FireStore using Firebase Admin SDK. The documentation for this is scant and/or written for other languages.
Anyone have any examples or links to dotnet core documentation to do this as I've spent all day trying to figure this out?
I've got a simple function as per: https://cloud.google.com/functions/docs/quickstart-dotnet#whats-next
and I see some tests that give a clue to how some of the SDK works: https://github.com/firebase/firebase-admin-dotnet/blob/f6babbd4e59655f01be4a43230b5be198fc4f8cd/FirebaseAdmin/FirebaseAdmin.Snippets/FirebaseAuthSnippets.cs#L608-L629
using Google.Cloud.Functions.Framework;
using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;
using FirebaseAdmin;
using FirebaseAdmin.Auth;
using Microsoft.Extensions.Logging;
using Google.Apis.Auth.OAuth2;
namespace HelloHttpFunction
{
public class Function : IHttpFunction
{
private readonly ILogger _logger;
public Function(ILogger<Function> logger) =>
_logger = logger;
//how to use firebase auth to check token and get uid from calling client
//how to read a set of docs from firestore
//already setup the Google environment variables
public async Task HandleAsync(HttpContext context)
{
HttpRequest request = context.Request;
// this my all guesswork below:
FirebaseApp.Create(new AppOptions()
{
Credential = GoogleCredential.GetApplicationDefault(),
});
FirebaseToken decodedToken = await FirebaseAuth.DefaultInstance.VerifyIdTokenAsync(idToken);
string uid = decodedToken.Uid;
var user = FirebaseAuth.DefaultInstance.GetUserAsync(uid);
await context.Response.WriteAsync("Hello, Functions Framework. ");
}
}
}

Adding an Authorization header to a WCF scaffolded SOAP web service

Disclaimer: I have not worked with SOAP web services ever. At all. Not even a little bit. So the concept of channels and WCF scaffolding has got me a bit confused, hence I'm here.
I have been asked to integrate to a SOAP XML web service which uses basic authentication. (e.g. Authorization header, Basic xxxxxxxxxxxxxxxxxxxxxxxxxxxx <- which is a Base64 encoded username:password). My project is in .NET Core using C#.
I have used Visual Studio WCF connected service discovery to produce scaffolding code which has served me very well for instantiating the required objects etc, however my issue is I've been asked to use Basic authentication, and I have no idea where to inject this code into the scaffolding that's been produced. I have worked with basic authentication before, so I understand 'how' to do it, for things like REST APIs etc. Just username:password, base64 encode and add to Authorization header. However, I am unsure how to do this for this scaffolded SOAP web service.
The code that i believe can be injected into every request, to add your custom headers, is:
using (OperationContextScope scope = new OperationContextScope(IContextChannel or OperationContext)
{
OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = new HttpRequestMessageProperty()
{
Headers =
{
{ "MyCustomHeader", Environment.UserName },
{ HttpRequestHeader.UserAgent, "My Custom Agent"}
}
};
// perform proxy operations...
}
The OperationContextScope expects either an IContextChannel or OperationContext. I am stuck as to what to add here. If I look at my scaffolded code, I can find the 'client' for the web service, here:
public partial class POSUserInformationManagerV1_2Client : System.ServiceModel.ClientBase<McaEndpointPosUserInformation.POSUserInformationManagerV1_2>, McaEndpointPosUserInformation.POSUserInformationManagerV1_2
And I can find the 'channel' here, but it's just another interface, that doesn't have any contracts specified?
[System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Tools.ServiceModel.Svcutil", "2.0.2")]
public interface POSUserInformationManagerV1_2Channel : McaEndpointPosUserInformation.POSUserInformationManagerV1_2, System.ServiceModel.IClientChannel
{
}
I looked up ChannelBase, and it seems like it should accept a variety of objects that implement one or another channel interface (including IClientChannel, which the scaffolded POSUserInformationManagerV1_2Channel uses)
protected class ChannelBase<T> : IDisposable, IChannel, ICommunicationObject, IOutputChannel, IRequestChannel, IClientChannel, IContextChannel, IExtensibleObject<IContextChannel> where T : class
{
protected ChannelBase(ClientBase<T> client);
[SecuritySafeCritical]
protected IAsyncResult BeginInvoke(string methodName, object[] args, AsyncCallback callback, object state);
[SecuritySafeCritical]
protected object EndInvoke(string methodName, object[] args, IAsyncResult result);
But I'm still stuck on what I can put into the OperationContextScope to connect it appropriately to the 'channel'. I've tried POSUserInformationManagerV1_2Client and the relevent Channel interface, but neither will convert to an IContextChannel. Does anyone have any ideas/thoughts?
EDIT: Here is where I am trying to inject the code to add the Auth HTTP header:
public System.Threading.Tasks.Task<McaEndpointPosUserInformation.requestUserInformationResponse> requestUserInformationAsync(McaEndpointPosUserInformation.requestUserInformation request)
{
using (OperationContextScope scope = new OperationContextScope(request)
{
OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = new HttpRequestMessageProperty()
{
Headers =
{
{ "MyCustomHeader", Environment.UserName },
{ HttpRequestHeader.UserAgent, "My Custom Agent"}
}
};
// perform proxy operations...
}
return base.Channel.requestUserInformationAsync(request);
}
The issue turned out to be not setting up the transport security to be 'Basic' through the use of:
// Set the binding. Without this, the WCF call will be made as anonymous
var binding = new BasicHttpsBinding();
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;

Pass username from client to every WCF Service calls

I'm new to .NET and WCF framework. Currently, I'm building a simple windows application to consume WCF service. The windows client need to pass username parameter to WCF Service to save to database. How can I do that without passing parameter in every service requests ?
One thing to note is this service will call a method in another project to save to database , so actually I want to access the username parameter at this project layer.
Form1.cs
public async void Save()
{
using(var client = new MyChannelFactory<WCFService>("WCFService"))
{
await Task.Run(() => client.Proxy.SaveData());
}
}
WCFService.cs
public void SaveData()
{
var _dataBL = new DataBL();
_dataBL.SaveData();
}
DataBL.cs
public void SaveData();
{
//need to get username from client
string user = GetUserName();
//save to database
}
Something to note:
WCFService.cs and DataBL.cs are in different projects.
I'm not adding Service Reference to client project, instead I'm using a ChannelFactory to create service proxy.
I'm using wsHttpBinding
I'm not using Windows Authentication
This should be a common request but after read many articles from internet, I still couldn't make it work.
Thanks for your help.

How can I pass a SSL certificate to Nowin when using Nancy

So I am using Nancy with Nowin.
The beauty of using Nowin is I don't have to mess around with various Windows commands to set up a simple web server. According to the Nowin readme I can configure SSL using the following line
builder.SetCertificate(new X509Certificate2("certificate.pfx", "password"));
However, when using Nancy I don't seem to have access to this Server builder class. Everything seems to happen magically behind the scenes.
Any ideas how I can pass the certificate through to Nowin?
Make sure you have the Nancy.Owin package installed.
Use code like this to start the server up:
.
using System;
using System.Net;
using System.Threading.Tasks;
using Nancy.Owin;
using Nowin;
public class Program
{
static void Main(string[] args)
{
var myNancyAppFunc = NancyMiddleware.UseNancy()(NancyOptions options =>
{
// Modify Nancy options if desired;
return Task.FromResult(0);
});
using (var server = ServerBuilder.New()
.SetOwinApp(myNancyAppFunc)
.SetEndPoint(new IPEndPoint(IPAddress.Any, 8080))
.SetCertificate(new X509Certificate2("certificate.pfx", "password"))
.Build()
)
{
server.Start();
Console.WriteLine("Running on 8080");
Console.ReadLine();
}
}
}
If you look at this document, it says the following:
Configuration of OWIN
It'll just be there if the host sends it on.
If you use IIS as a host. You'll need to do the same config as with Aspnet. And you'll need an OWIN Aspnet host that supports the ClientCertificate. The one in the OWIN demo in Nancy does. The one by #prabirshrestha also does.
In the OWIN Demo, check this line:
if (request.ClientCertificate != null && request.ClientCertificate.Certificate.Length != 0)
{
env[OwinConstants.ClientCertificate] = new X509Certificate(request.ClientCertificate.Certificate);
}
Hope it helps you, good luck.
I think you should follow by the way described in this article: https://msdn.microsoft.com/en-us/magazine/dn451439.aspx
At first you are creating web server according with Nowin documentation and after that you are adding Nancy as pipeline component. I tested this way with NowingSample (from Nowin package) and it works.

Categories