Azure Data Lake Store File read using SSIS Script Component - azure

Appreciate your suggestions.
My Requirement is, Read json file from ADLS using SSIS and load into SQL table
Implementation:
I have implemented the code to read json file content in .Net Console app. This is working fine in Console app. I copied the same code in SSIS Script component, but it throws "The type initializer for 'Microsoft.Azure.DataLake.Store.AdlsClient' threw an exception" exception in AdlsClient.CreateClient.
using Microsoft.Rest;
using Microsoft.Rest.Azure.Authentication;
using Microsoft.Azure.Management.DataLake.Store;
using Microsoft.Azure.DataLake.Store;
using Microsoft.Azure.DataLake.Store.AclTools;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
JObject results = new JObject();
string applicationId = "<appid>;
string secretKey = <secretekey>;
string tenantId = <tenantid>;
string adlsAccountName = "<ADLSNAME>.azuredatalakestore.net";
ServiceClientCredentials creds = ApplicationTokenProvider.LoginSilentAsync(tenantId, applicationId, secretKey).Result;
AdlsClient adlsClient = AdlsClient.CreateClient(adlsAccountName, creds);
string srcPath = #"/InputFiles/1636274001230002_20180621_104427.json";
using (StreamReader readStream = new
StreamReader(adlsClient.GetReadStream(srcPath)))
{
var p2Object = JsonConvert.DeserializeObject(readStream.ReadToEnd());
results = JObject.Parse(p2Object.ToString());
}
date = ((string)results["eeData"][0]["startDate"]);
machine = ((string)results["eeData"][0]["machineName"]);
ppl = ((string)results["eeData"][0]["ppl"]);

The issue is with the reference path missing in SSIS Script component for the 3rd party DLLs. In Console App I am able to install NuGet package manager. But in SSIS Script component, the NuGet package installation is failed and SSIS component is missing the reference. The below code will force the script component compiler to refer the DLLs from the given path.
Add this code above PreExecute() / Main() method.
static ScriptMain()
{
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
}
static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
if (args.Name.Contains("Newtonsoft.Json"))
{
return System.Reflection.Assembly.LoadFile(#"C:\Program Files\Microsoft SDKs\Azure\.NET SDK\v2.9\ToolsRef\Newtonsoft.Json.dll");
}
if (args.Name.Contains("Microsoft.Azure.DataLake.Store"))
{
return System.Reflection.Assembly.LoadFile(#"C:\Program Files\WindowsPowerShell\Modules\AzureRM.DataLakeStore\5.2.0\Microsoft.Azure.DataLake.Store.dll");
}
if (args.Name.Contains("Microsoft.Rest.ClientRuntime.Azure.Authentication"))
{
return System.Reflection.Assembly.LoadFile(#"C:\Program Files\WindowsPowerShell\Modules\Azure\5.1.2\StorSimple\Microsoft.Rest.ClientRuntime.Azure.Authentication.dll");
}
if (args.Name.Contains("Microsoft.Rest.ClientRuntime"))
{
return System.Reflection.Assembly.LoadFile(#"C:\Program Files\WindowsPowerShell\Modules\Azure\5.1.2\Services\Microsoft.Rest.ClientRuntime.dll");
}
if (args.Name.Contains("NLog"))
{
return System.Reflection.Assembly.LoadFile(#"C:\Users\<user>\source\repos\Integration Services Project2\NLog.dll");
}
return null;
}

Related

Azure Cognitive Service\Computer Visio\OCR - Can I use it into into WebSite C#

I'm trying to use Azure Ocr into my website c#.
I added the package Microsoft.Azure.CognitiveServices.Vision.ComputerVision and I wrote code, with key and endpoint of my subscription.
static string subscriptionKey = "mykey";
static string endpoint = "https://myocr.cognitiveservices.azure.com/";
private const string ANALYZE_URL_IMAGE = "https://raw.githubusercontent.com/Azure-Samples/cognitive-services-sample-data-files/master/ComputerVision/Images/printed_text.jpg";
protected void Page_Load(object sender, EventArgs e)
{
// Create a client
ComputerVisionClient client = Authenticate(endpoint, subscriptionKey);
// Analyze an image to get features and other properties.
AnalyzeImageUrl(client, ANALYZE_URL_IMAGE).Wait();
}
public static ComputerVisionClient Authenticate(string endpoint, string key)
{
ComputerVisionClient client =
new ComputerVisionClient(new ApiKeyServiceClientCredentials(key))
{ Endpoint = endpoint };
return client;
}
public static async Task AnalyzeImageUrl(ComputerVisionClient client, string imageUrl)
{
// Read text from URL
var textHeaders = await client.ReadAsync(imageUrl);
...
}
It seems all ok, but at line
var textHeaders = await client.ReadAsync(urlFile);
website crashes.
I don't understand why. No error, it's just stopped.
So I ask: azure ocr can to be use only with console app?
EDIT
The code is ok for ConsoleApp and WebApp but not working for my asp.net WEBSITE.
Could be a problem with async?
We can use OCR with web app also,I have taken the .net core 3.1 webapp in Visual Studio and installed the dependency of Microsoft.Azure.CognitiveServices.Vision.ComputerVision by selecting the check mark of include prerelease as shown in the below image:
After creating computer vision resource in Azure Portal, copied the key and endpoint from there and used inside the c# code.
using System;
using System.Collections.Generic;
using Microsoft.Azure.CognitiveServices.Vision.ComputerVision;
using Microsoft.Azure.CognitiveServices.Vision.ComputerVision.Models;
using System.Threading.Tasks;
using System.IO;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Threading;
using System.Linq;
namespace ComputerVisionQuickstart
{
class Program
{
// Add your Computer Vision subscription key and endpoint
static string subscriptionKey = "c1****b********";
static string endpoint = ".abc.cognitiveservices.azure.com/";
private const string READ_TEXT_URL_IMAGE = "https://raw.githubusercontent.com/Azure-Samples/cognitive-services-sample-data-files/master/ComputerVision/Images/printed_text.jpg";
static void Main(string[] args)
{
Console.WriteLine("Azure Cognitive Services Computer Vision - .NET quickstart example");
Console.WriteLine();
ComputerVisionClient client = Authenticate(endpoint, subscriptionKey);
// Extract text (OCR) from a URL image using the Read API
ReadFileUrl(client, READ_TEXT_URL_IMAGE).Wait();
}
public static ComputerVisionClient Authenticate(string endpoint, string key)
{
ComputerVisionClient client =
new ComputerVisionClient(new ApiKeyServiceClientCredentials(key))
{ Endpoint = endpoint };
return client;
}
public static async Task ReadFileUrl(ComputerVisionClient client, string urlFile)
{
Console.WriteLine("----------------------------------------------------------");
Console.WriteLine("READ FILE FROM URL");
Console.WriteLine();
// Read text from URL
var textHeaders = await client.ReadAsync(urlFile);
// After the request, get the operation location (operation ID)
string operationLocation = textHeaders.OperationLocation;
Thread.Sleep(2000);
// Retrieve the URI where the extracted text will be stored from the Operation-Location header.
// We only need the ID and not the full URL
const int numberOfCharsInOperationId = 36;
string operationId = operationLocation.Substring(operationLocation.Length - numberOfCharsInOperationId);
// Extract the text
ReadOperationResult results;
Console.WriteLine($"Extracting text from URL file {Path.GetFileName(urlFile)}...");
Console.WriteLine();
do
{
results = await client.GetReadResultAsync(Guid.Parse(operationId));
}
while ((results.Status == OperationStatusCodes.Running ||
results.Status == OperationStatusCodes.NotStarted));
// Display the found text.
Console.WriteLine();
var textUrlFileResults = results.AnalyzeResult.ReadResults;
foreach (ReadResult page in textUrlFileResults)
{
foreach (Line line in page.Lines)
{
Console.WriteLine(line.Text);
}
}
Console.WriteLine();
}
}
}
The above code is taken from the Microsoft Document.
I can be able to read the text inside the image successfully as shown in the below screenshot:

Why does my Azure V2 time function crashes with newtonsoft reference?

I have a simple timer based azure function that crashes with the following message
I have added the nuget package for newtonsoft.Json so I am not sure why this is a problem.
[1/11/2018 07:00:26] Executed 'PimDataFeeder' (Failed, Id=291e9147-7f57-4fd3-887d-a8001afc8230)
[1/11/2018 07:00:26] System.Private.CoreLib: Exception while executing function: PimDataFeeder. System.Private.CoreLib: Could not load file or assembly 'Newtonsoft.Json, Version=11.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed'. Could not find or load a specific file. (Exception from HRESULT: 0x80131621). System.Private.CoreLib: Could not load file or assembly 'Newtonsoft.Json, Version=11.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed'.
---- EDIT ----
The simple function looks like this, basically it downloads a file from a remote destination and manipulates it in memory before writing it into a CosmosDB instance, or at least thats the idea once it starts working. Putting a break point in the loop tells me that the first loop iteration works and indeed the first line from the string is split properly and then follows the crash
using System;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Host;
using System.Net.Http;
using System.Net.Http.Handlers;
using System.Net.Http.Headers;
using System.IO.Compression;
using System.IO;
using System.Text;
using System.Net;
using Microsoft.Azure.Documents;
using Microsoft.Azure.Documents.Client;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using System.ComponentModel.DataAnnotations;
namespace NWCloudPimDataFeeder
{
public static class PimDataFeeder
{
[FunctionName("PimDataFeeder")]
public static async System.Threading.Tasks.Task RunAsync([TimerTrigger("0 */15 * * * *")]TimerInfo myTimer, TraceWriter log)
{
// The endpoint to your cosmosdb instance
var endpointUrl = "https://example.com";
// The key to you cosmosdb
var key = "XXX";
// The name of the database
var databaseName = "XXX";
// The name of the collection of json documents
var databaseCollection = "XXX";
log.Info($"C# Timer trigger function executed at: {DateTime.Now}");
HttpClientHandler handler = new HttpClientHandler()
{
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
};
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer XXX");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage file = await client.GetAsync("https://example.com");
var content = await file.Content.ReadAsByteArrayAsync();
MemoryStream originalFileStream = new MemoryStream(content);
using (GZipStream decompressionStream = new GZipStream(originalFileStream, CompressionMode.Decompress))
{
MemoryStream decompressedFileStream = new MemoryStream();
decompressionStream.CopyTo(decompressedFileStream);
byte[] fileResult = new byte[decompressedFileStream.Length];
decompressedFileStream.Position = 0;
decompressedFileStream.Read(fileResult, 0, fileResult.Length);
string result = System.Text.Encoding.UTF8.GetString(fileResult);
//log.Info(result);
foreach (var singleItem in result.Split(new string[] { "\r\n", "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries))
{
log.Info("singleItem looks like: " +singleItem);
log.Info("In the loop");
var itemWrapper = new ItemWrapper { NWID = Guid.NewGuid(), Item = singleItem, DocumentType = "Item"};
// Create a cosmosdb client
using (var docClient = new DocumentClient(new Uri(endpointUrl), key))
{
// Save the document to cosmosdb
docClient.CreateDocumentAsync(UriFactory.CreateDocumentCollectionUri(databaseName, databaseCollection), itemWrapper)
.GetAwaiter().GetResult();
}
}
}
}
}
public class ItemWrapper
{
public Guid NWID { get; set; }
[Required]
[JsonProperty("item")]
public string Item { get; set; }
[Required]
[JsonProperty("documentType")]
public string DocumentType { get; set; }
}
}
Right now the Cli and Runtime is output as below when we debug function in VS. And the function project is created with Microsoft.NET.Sdk.Functions 1.0.23(>=1.0.14) references Newtonsoft.Json 11.0.2 by default.
Azure Functions Core Tools (2.1.748 Commit hash: 5db20665cf0c11bedaffc96d81c9baef7456acb3)
Function Runtime Version: 2.0.12134.0
I can only repro the problem with some old Function runtime, which still requires v10 Newtonsoft.Json. So check Function runtime version and make sure VS consumes the latest.
Download and set cli manually
Delete old Function CLI using by VS. Remove subfolders under %localappdata%\AzureFunctionsTools\Releases.
Delete template engine consumed by VS %userprofile%\.templateengine.
Go to CLI feed to download latest cli, right now it's feed 2.10.1 and CLI 2.1.748.
Go to %localappdata%\AzureFunctionsTools\Releases and create folder 2.10.1.
Decompress the zip and rename it to cli, drag it under 2.10.1.
Copy templates folder under cli to 2.10.1, and rename two files inside by removing version. e.g itemTemplates.2.0.0-10300.nupkg to itemTemplates.nupkg.
Create a manifest.json under 2.10.1 as below and change username.
{
"CliEntrypointPath": "C:\\Users\\UserName\\AppData\\Local\\AzureFunctionsTools\\Releases\\2.10.1\\cli\\func.exe",
"FunctionsExtensionVersion": "~2",
"MinimumRuntimeVersion": "2.1",
"ReleaseName": "2.10.1",
"RequiredRuntime": ".NET Core",
"SdkPackageVersion": "1.0.23",
"TemplatesDirectory": "C:\\Users\\UserName\\AppData\\Local\\AzureFunctionsTools\\Releases\\2.10.1\\templates"
}
The folder structure should be like this
After restarting VS, everything should work as expected.
These errors are often times caused by not having the latest version of the Functions SDK/Tools installed. The reference to Newtonsoft 11.0.0 suggests that this might be the be the case (latest version is 11.0.2). You can navigate to Tools -> Extensions and Updates -> Updates (bottom left of window) in VS to check for updates to Azure Functions tooling. Once you have the latest update, trying re-creating the function to see if it works.

A namespace cannot directly contain members in the Azure Function App

TARGET: Do the Azure Function tutorial on and copied code, but got several errors when executing locally on VS2017. I appreciate you help.
https://www.cyotek.com/blog/upload-data-to-blob-storage-with-azure-functions
ERROR 1 - related to Run:
CS0116 A namespace cannot directly contain members such as fields or methods UploadToBlobFunctionApp C:\AzureFunctions\UploadToBlobFunctionApp\UploadToBlobFunctionApp\UploadToBlobFunction.cs 15 Active
ERROR 2 - related to Task CreateBlob:
CS0116 A namespace cannot directly contain members such as fields or methods UploadToBlobFunctionApp
C:\AzureFunctions\UploadToBlobFunctionApp\UploadToBlobFunctionApp\UploadToBlobFunction.cs 45 Active
ERROR 3 - related to await CreateBlob:
CS0103 The name 'CreateBlob' does not exist in the current context UploadToBlobFunctionApp C:\AzureFunctions\UploadToBlobFunctionApp\UploadToBlobFunctionApp\UploadToBlobFunction.cs 36 Active
CODE Function.cs:
using System;
using System.Configuration;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Azure;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Host;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
HttpStatusCode result;
string contentType;
result = HttpStatusCode.BadRequest;
contentType = req.Content.Headers?.ContentType?.MediaType;
if (contentType == "application/json")
{
string body;
body = await req.Content.ReadAsStringAsync();
if (!string.IsNullOrEmpty(body))
{
string name;
name = Guid.NewGuid().ToString("n");
await CreateBlob(name + ".json", body, log);
result = HttpStatusCode.OK;
}
}
return req.CreateResponse(result, string.Empty);
}
private async static Task CreateBlob(string name, string data,
TraceWriter log)
{
string accessKey;
string accountName;
string connectionString;
CloudStorageAccount storageAccount;
CloudBlobClient client;
CloudBlobContainer container;
CloudBlockBlob blob;
accessKey = "qwertyw4VhRajxlZn9C4hTMB8oSwE4klNUsvTy9VeTCIQ11111vFVVGExDwJ+JUboFv2B79j+W6foqLWE92w==";
accountName = "mystorage";
connectionString = "DefaultEndpointsProtocol=https;AccountName=" + accountName + ";AccountKey=" + accessKey + ";EndpointSuffix=core.windows.net";
storageAccount = CloudStorageAccount.Parse(connectionString);
client = storageAccount.CreateCloudBlobClient();
container = client.GetContainerReference("functionupload");
await container.CreateIfNotExistsAsync();
blob = container.GetBlockBlobReference(name);
blob.Properties.ContentType = "application/json";
using (Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(data)))
{
await blob.UploadFromStreamAsync(stream);
}
}
The example that you are referencing is using scripted functions (csx file). They are mostly used while editing code directly in Azure portal.
I think you are trying to create a precompiled application with csproj and cs files. In this case, your code should be a valid C#, i.e. all methods should be inside classes.
Have a look at this example.
You can also use attributes to mark your functions and triggers instead of authoring function.json manually, see examples here.

Getting NULL terms when accesing TermCollection from SharePoint Online via CSOM in an Azure Function

I am trying to expose a REST API using Azure Functions which returns terms from a specific termset in SharePoint Online using CSOM and C#.
I can definitely invoke this exact same CSOM code from a console app and from an Azure API app and it is able to loop through the terms and output to console or the HTTP response successfully.
However, when the code below is invoked from the Azure Function host, it ALWAYS find a collection of NULL term objects, when looping through the TermCollection or the IEnumerable<Term> (I’ve tried by using ClientContext.LoadQuery on TermSet.GetAllTerms(), as well as by just loading the TermCollection via the TermSet.Terms property).
As soon as the iterator hits a term in the foreach (which I’ve also tried as just a LINQ Select), it thinks that the item is NULL, so calling properties on it throws the NullReferenceException. I cannot reproduce the behavior from the console app or from the API app calling into the same code - it just works as expected there and retrieves each Term object.
Why is this happening when SAME CODE is invoked from different hosts??
Why would this happen in the Azure Functions host, but not in Console app or the Azure API app?
What is the difference when invoked from an Azure Function host??
I would really like to use Azure Functions for the consumption pricing benefits, so I don't have to host this in an App Service.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security;
using Microsoft.SharePoint.Client;
using Microsoft.SharePoint.Client.Taxonomy;
namespace CsomTaxonomyHelper
{
public class TermSearch
{
private readonly ClientContext ctx;
public TermSearch(ClientContext context)
{
if (context == null)
throw new ArgumentNullException(nameof(context));
ctx = context;
}
public IEnumerable<TermViewModel> GetTerms(Guid termSetId)
{
var taxonomySession = TaxonomySession.GetTaxonomySession(ctx);
var termStore = taxonomySession.GetDefaultSiteCollectionTermStore();
var termSet = termStore.GetTermSet(termSetId);
//get flat list of terms, so we don't make recursive calls to SPO
var allTerms = ctx.LoadQuery(termSet.GetAllTerms().IncludeWithDefaultProperties());
ctx.ExecuteQuery();
return ToViewModel(allTerms);
}
static IEnumerable<TermViewModel> ToViewModel(IEnumerable<Term> allTerms)
{
var results = allTerms.Select(term => new TermViewModel
{
Id = term.Id, //BOOM! <-- within the context of an Azure Function the "allTerms" IEnumerable is a list of nulls
Name = term.Name,
ParentId = TryGetParentId(term)
});
return results;
}
static Guid? TryGetParentId(Term term)
{
try
{
if (term.Parent.IsPropertyAvailable("Id"))
return term.Parent.Id;
}
catch (ServerObjectNullReferenceException) { }
return null;
}
}
public class PasswordString
{
public SecureString SecurePassword { get; private set; }
public PasswordString(string password)
{
SecurePassword = new SecureString();
foreach (char c in password.ToCharArray())
{
SecurePassword.AppendChar(c);
}
SecurePassword.MakeReadOnly();
}
}
}
Here's the "run.csx" function, invoking the code above which has been compiled into a DLL and placed in the Bin folder of the Azure Function:
#r "CsomTaxonomyHelper.dll"
#r "Newtonsoft.Json"
using System.Net;
using Microsoft.SharePoint.Client;
using Microsoft.SharePoint.Client.Taxonomy;
using CsomTaxonomyHelper;
using Newtonsoft.Json;
static TraceWriter _log = null;
public static HttpResponseMessage Run(HttpRequestMessage req, TraceWriter log)
{
_log = log;
_log.Info("C# HTTP trigger function processed a request. Getting mmd terms from SPO...");
var terms = GetFocusAreas();
var result = JsonConvert.SerializeObject(terms);
return req.CreateResponse(HttpStatusCode.OK, result);
}
static IEnumerable<TermViewModel> GetFocusAreas()
{
string spSiteUrl = System.Environment.GetEnvironmentVariable("SPOSiteUrl", EnvironmentVariableTarget.Process);
string userName = System.Environment.GetEnvironmentVariable("SPOUserName", EnvironmentVariableTarget.Process);
string password = System.Environment.GetEnvironmentVariable("SPOPassword", EnvironmentVariableTarget.Process);
var securePwd = new PasswordString(password).SecurePassword;
using (var ctx = new ClientContext(spSiteUrl))
{
ctx.Credentials = new SharePointOnlineCredentials(userName, securePwd);
ctx.ExecuteQuery();
_log.Info("Logged into SPO service.");
var search = new TermSearch(ctx);
try
{
var result = search.GetTerms(new Guid("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"));
return result;
}
catch (Exception ex)
{
_log.Error(ex.Message, ex);
throw;
}
}
}
Project.json:
{
"frameworks": {
"net46":{
"dependencies": {
"Microsoft.SharePointOnline.CSOM": "16.1.6112.1200"
}
}
}
}
Here's the screenshot of the local debugger, when using the Azure Functions CLI to debug this (you can see that it did find 10 items in the collection, but all items are null):
Not the solution, but adding to the conversation - I was able to test with PnP-PowerShell (2017-Feb). Terms were just added.
SPO, CSOM and PnP-PowerShell.
Installing PnP-PowerShell to a PowerShell function:

How to get full list of CloudConfiguration from inside a web service at runtime?

ConfigurationManager has AppSettings name-value collection but CloudConfigurationManager has only GetSetting(string) method where you can get the config settings 1 by 1 if you know the key.
Is there a way to get the whole config of the role runtime?
The root cause is that I want to make strong typed configuration in order to abstract it away and make my code more testable. Using CloudConfigurationManager directly is implicit dependency which I want to remove with an abstraction which I want to stub in tests. So I find this practical. Which brings me to my question.
I do not want to use library like fx.configuration.azure because I will have to carry its dependency altogether because it requires inheritance of a base class.
AFAIK, there's no direct method available which will give you this information.
However there's a workaround that you can use. It involves making use of Service Management API's Get Deployment operation. This operation will return an XML and one of the element there is Configuration which contains your service configuration file in Base64 encoded format. You can read this element, convert it into string and parse the XML to get to ConfigurationSettings elements. It's child elements contains all the settings.
For this, you could either write your own wrapper over Service Management REST API or make use of Azure Management Library.
UPDATE
So here's a sample code for listing all configuration settings from Service Configuration File using Azure Management Library. It's a simple console app hacked together in very short amount of time thus has a lot of scope of improvement :). For management certificate, I have used the data from Publish Setting File.
You just have to install Azure Management Library Nuget Package in your console application:
Install-Package Microsoft.WindowsAzure.Management.Libraries
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.Management.Compute;
using System.Security.Cryptography.X509Certificates;
using System.Xml.Linq;
namespace ReadConfigurationSettingsUsingAzureManagementLibrary
{
class Program
{
static string subscriptionId = "<subscription-id>";
static string managementCertContents = "<Base64 Encoded Management Certificate String from Publish Setting File>";//Certificate string from Azure Publish Settings file
static string cloudServiceName = "<your cloud service name>";
static string ns = "http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration";
static void Main(string[] args)
{
var managementCetificate = new X509Certificate2(Convert.FromBase64String(managementCertContents));
var credentials = new CertificateCloudCredentials(subscriptionId, managementCetificate);
var computeManagementClient = new ComputeManagementClient(credentials);
var response = computeManagementClient.HostedServices.GetDetailed(cloudServiceName);
var deployment = response.Deployments.FirstOrDefault(d => d.DeploymentSlot == Microsoft.WindowsAzure.Management.Compute.Models.DeploymentSlot.Production);
if (deployment != null)
{
var config = deployment.Configuration;
XElement configXml = XElement.Parse(config);
var roles = configXml.Descendants(XName.Get("Role", ns));
foreach (var role in roles)
{
Console.WriteLine(role.Attribute("name").Value);
Console.WriteLine("-----------------------------");
var configurationSettings = role.Element(XName.Get("ConfigurationSettings", ns));
foreach (var element in configurationSettings.Elements(XName.Get("Setting", ns)))
{
var settingName = element.Attribute("name").Value;
var settingValue = element.Attribute("value").Value;
Console.WriteLine(string.Format("{0} = {1}", settingName, settingValue));
}
Console.WriteLine("==========================================");
}
}
Console.ReadLine();
}
}
}
Here is an updated implementation which takes care if you are running in emulator or not and if you are running in local web server or not. After returning the dictionary it can be easily abstracted away from the whole application by Castle.DictionaryAdapter. I shared the code as template project on GitHub here. Here is an excerpt:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography.X509Certificates;
using System.Xml;
using System.Xml.Linq;
using Castle.Components.DictionaryAdapter;
using Core.Configuration.Interfaces;
using Microsoft.Azure;
using Microsoft.WindowsAzure.Management.Compute;
using Microsoft.WindowsAzure.Management.Compute.Models;
using Microsoft.WindowsAzure.ServiceRuntime;
namespace Core.Configuration
{
public class AzureServiceConfigurationProvider : IAzureServiceConfigurationProvider
{
private readonly string _subscriptionId;
// The Base64 Encoded Management Certificate string from Azure Publish Settings file
// download from https://manage.windowsazure.com/publishsettings/index
private readonly string _managementCertContents;
private readonly string _cloudServiceName;
private readonly string _serviceConfigurationNamespace;
public DefaultAzureServiceConfigurationProvider(IWebConfigSettings webConfigSettings)
{
_subscriptionId = webConfigSettings.SubscriptionId;
_managementCertContents = webConfigSettings.ManagementCertContents;
_cloudServiceName = webConfigSettings.CloudServiceName;
_serviceConfigurationNamespace = webConfigSettings.ServiceConfigurationNamespace;
}
public Dictionary<string, Dictionary<string, string>> GetConfigRaw()
{
Trace.WriteLine("DefaultAzureServiceConfigurationProvider->GetConfigRaw->Start");
var configuration = new Dictionary<string, Dictionary<string, string>>();
var configXml = GetConfigXml();
Trace.WriteLine("DefaultAzureServiceConfigurationProvider->GetConfigRaw->XmlExtracted");
var roles = configXml.Descendants(XName.Get("Role", _serviceConfigurationNamespace));
Trace.WriteLine("DefaultAzureServiceConfigurationProvider->GetConfigRaw->Roles : ");
foreach(var role in roles)
{
var roleConfiguration = new Dictionary<string, string>();
var roleName = role.Attribute("name").Value;
Trace.WriteLine("DefaultAzureServiceConfigurationProvider->GetConfigRaw->RoleName : " + roleName);
var configurationSettings = role.Element(XName.Get("ConfigurationSettings", _serviceConfigurationNamespace));
if (configurationSettings == null)
{
throw new InvalidOperationException("configurationSettings is null");
}
foreach(var element in configurationSettings.Elements(XName.Get("Setting", _serviceConfigurationNamespace)))
{
var settingName = element.Attribute("name").Value;
var settingValue = element.Attribute("value").Value;
Trace.WriteLine("DefaultAzureServiceConfigurationProvider->GetConfigRaw->settingName : " + settingName + " settingValue : " + settingValue);
roleConfiguration.Add(settingName, settingValue);
}
configuration.Add(roleName, roleConfiguration);
}
return configuration;
}
public IAzureServiceConfiguration GetConfig()
{
var configFactory = new DictionaryAdapterFactory();
IAzureServiceConfiguration config;
try
{
var rawAzureServiceConfig = GetConfigRaw();
Trace.WriteLine("DefaultAzureServiceConfigurationProvider->GetConfig :");
var rawAzureWebServiceConfig = rawAzureServiceConfig["Core.Web"];
config = configFactory.GetAdapter<IAzureServiceConfiguration>(rawAzureWebServiceConfig);
config = ComplementConfigurationFromConfigurationManager(config);
}
catch(Exception exception)
{
// happens in some projects when using Full Emulator
// so we fallback to cloudconfigurationmanager
// this is not bad since we have isolated it in configuration assembly
Trace.WriteLine(exception.Message);
Trace.WriteLine(exception.StackTrace);
Hashtable hashConfig = GetConfigFromConfigurationManager();
config = configFactory.GetAdapter<IAzureServiceConfiguration>(hashConfig);
}
return config;
}
private IAzureServiceConfiguration ComplementConfigurationFromConfigurationManager(IAzureServiceConfiguration config)
{
Trace.WriteLine("Complementing configuration");
var azureConfigType = config.GetType();
foreach(PropertyInfo property in config.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly))
{
var xmlConfigValue = CloudConfigurationManager.GetSetting(property.Name);
var liveConfigPropValue = (string)azureConfigType.GetProperty(property.Name).GetValue(config, null);
if(string.IsNullOrEmpty(liveConfigPropValue))
{
Trace.WriteLine(property.Name + " in live config is empty. Complementing with '" + xmlConfigValue + "' from ConfigurationManager.");
property.SetValue(config, xmlConfigValue);
}
// do something with the property
}
return config;
}
private Hashtable GetConfigFromConfigurationManager()
{
Hashtable hashConfig = new Hashtable();
var configProperties = typeof(IAzureServiceConfiguration).GetProperties();
foreach(PropertyInfo prop in configProperties)
{
hashConfig.Add(prop.Name, CloudConfigurationManager.GetSetting(prop.Name));
}
return hashConfig;
}
private XElement GetConfigXml()
{
XElement configXml = null;
Trace.WriteLine("DefaultAzureServiceConfigurationProvider->GetConfigXml");
if(!RoleEnvironment.IsAvailable/*as local web project*/ || RoleEnvironment.IsEmulated /*as azure emulator project*/)
{
Trace.WriteLine("DefaultAzureServiceConfigurationProvider->GetConfigXml->!RoleEnvironment.IsAvailable || RoleEnvironment.IsEmulated");
try
{
var localConfigFile =
new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory).Parent.EnumerateFiles(
"*Local.cscfg", SearchOption.AllDirectories).FirstOrDefault();
XmlDocument doc = new XmlDocument();
doc.Load(localConfigFile.FullName);
configXml = XElement.Parse(doc.InnerXml);
}
catch(Exception exception) // happens in some projects when using Full Emulator
{
Trace.WriteLine(exception.Message);
Trace.WriteLine(exception.StackTrace);
throw; // intended - just marking - will catch it above
}
}
else
{
Trace.WriteLine("DefaultAzureServiceConfigurationProvider->GetConfigXml->RoleEnvironment ->in cloud");
var managementCertificate = new X509Certificate2(Convert.FromBase64String(_managementCertContents));
var credentials = new CertificateCloudCredentials(_subscriptionId, managementCertificate);
var computeManagementClient = new ComputeManagementClient(credentials);
var response = computeManagementClient.HostedServices.GetDetailed(_cloudServiceName);
var deployment = response.Deployments.FirstOrDefault(d => d.DeploymentSlot == DeploymentSlot.Production);
if(deployment != null)
{
var config = deployment.Configuration;
configXml = XElement.Parse(config);
}
}
return configXml;
}
}
internal static class TypeHelpers
{
public static bool IsNumber(this object value)
{
return value is sbyte
|| value is byte
|| value is short
|| value is ushort
|| value is int
|| value is uint
|| value is long
|| value is ulong
|| value is float
|| value is double
|| value is decimal;
}
public static bool IsString(this object value)
{
return value is string;
}
}
}

Resources