System.ArgumentException: 'Should specify SharedAccessKeyName' - c#

I'm getting this error from Azure IoT Provisioning Service when creating the provisioning client.
System.ArgumentException: 'Should specify SharedAccessKeyName'
I copied the Connection String from the Portal, what could be wrong?
using System;
using System.IO;
using System.Reflection;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
using Microsoft.Azure.Devices.Provisioning.Service;
namespace EnrollmentApp
{
class Program
{
private static string ProvisioningConnectionString = "HostName=happybeerhub-us.azure-devices.net;DeviceId=test-device-01;SharedAccessKey=tawpddfqUt3EHZg9a5tUzQ5fjros7zMhKsZbmuXzwXE=";
private static string EnrollmentGroupId = "test";
private static string X509RootCertPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), #"key.pfx");
static void Main(string[] args)
{
RunSample().GetAwaiter().GetResult();
Console.WriteLine("\nHit <Enter> to exit ...");
Console.ReadLine();
}
public static async Task RunSample()
{
Console.WriteLine("Starting sample...");
using (ProvisioningServiceClient provisioningServiceClient =
ProvisioningServiceClient.CreateFromConnectionString(ProvisioningConnectionString))
{
#region Create a new enrollmentGroup config
Console.WriteLine("\nCreating a new enrollmentGroup...");
var certificate = new X509Certificate2(X509RootCertPath);
Attestation attestation = X509Attestation.CreateFromRootCertificates(certificate);
EnrollmentGroup enrollmentGroup =
new EnrollmentGroup(
EnrollmentGroupId,
attestation)
{
ProvisioningStatus = ProvisioningStatus.Enabled
};
Console.WriteLine(enrollmentGroup);
#endregion
#region Create the enrollmentGroup
Console.WriteLine("\nAdding new enrollmentGroup...");
EnrollmentGroup enrollmentGroupResult =
await provisioningServiceClient.CreateOrUpdateEnrollmentGroupAsync(enrollmentGroup).ConfigureAwait(false);
Console.WriteLine("\nEnrollmentGroup created with success.");
Console.WriteLine(enrollmentGroupResult);
#endregion
}
}
}
}

Well you are missing the SharedAccessKeyName so the validation tries to check it and as it is null in your case you get the exception.
As you can see in the ServiceConnectionStringBuilder.cs the correct connection string format is
/// A valid connection string shall be in the following format:
/// <code>
/// HostName=[ServiceName];SharedAccessKeyName=[keyName];SharedAccessKey=[Key]
/// </code>
Also in line 128 you can see the check which throws your exception:
if (string.IsNullOrWhiteSpace(SharedAccessKeyName))
{
throw new ArgumentException("Should specify SharedAccessKeyName");
}
Now you might think that ServiceConnectionStringBuilder.cs is not used by your code, but the call ProvisioningServiceClient.CreateFromConnectionString creates a new ProvisioningServiceClient instance, which in turn calls ServiceConnectionStringBuilder.Parse().
For more see ProvisioningServiceClient.cs in lines 82, 113 and 123.
SOLUTION:
To solve this you have to provide a SharedAccessKeyName. You should also consider using the IotHubConnectionStringBuilder for this which already checks your properties whhile building the connection string.
The questioner pointed out the key name is the deviceId according to this blog post here. Thus, the solution is to use SharedAccessKeyname=xx instead of DeviceId=xx.

Related

C# call method from different class with 'args' as a parameter

I'm writing a Discord Bot (Discord.net) and I found myself requiring to access some data on a google sheet using their APIs. Being that I thought it would be best to actually separate those two in two different class files I have tried summoning the Main method of the Google APIs into my program (after having renamed it "Sheets") like this in my Program.cs:
using Discord;
using Discord.WebSocket;
using System;
using System.IO;
using System.Threading.Tasks;
namespace WoM_Balance_Bot
{
public class Program
{
public static void Main(string[] args)
{
GoogleAPI GSheet = new GoogleAPI();
GSheet.Sheets();
new Program().MainAsync().GetAwaiter().GetResult();
}
private DiscordSocketClient _client;
public async Task MainAsync()
{
_client = new DiscordSocketClient();
_client.MessageReceived += CommandHandler;
_client.Log += Log;
var token = File.ReadAllText("bot-token.txt");
await _client.LoginAsync(TokenType.Bot, token);
await _client.StartAsync();
// Block this task until the program is closed.
await Task.Delay(-1);
}.......ecc
I tried writing the parameters to pass here in these parentheses like "string" and "args" but either I get the syntax wrong or I have a very wrong idea about what to pass exactly.
This is the actual content of GoogleAPI.cs, which is the other class file I created that has the Google Sheet APIs:
using Google.Apis.Auth.OAuth2;
using Google.Apis.Services;
using Google.Apis.Sheets.v4;
using Google.Apis.Sheets.v4.Data;
using Google.Apis.Util.Store;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
namespace WoM_Balance_Bot
{
public class GoogleAPI
{
// If modifying these scopes, delete your previously saved credentials
// at ~/.credentials/sheets.googleapis.com-dotnet-quickstart.json
private static readonly string[] Scopes = { SheetsService.Scope.SpreadsheetsReadonly };
private static readonly string ApplicationName = "wombankrolls";
public static void Sheets(string[] args)
{
UserCredential credential;
Console.WriteLine("if you read this then it's good");
using (var stream =
new FileStream("credentials.json", FileMode.Open, FileAccess.Read))
{
// The file token.json stores the user's access and refresh tokens, and is created
// automatically when the authorization flow completes for the first time.
string credPath = "token.json";
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
Scopes,
"user",
CancellationToken.None,
new FileDataStore(credPath, true)).Result;
Console.WriteLine("Credential file saved to: " + credPath);
}
// Create Google Sheets API service.
var service = new SheetsService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = ApplicationName,
});
// Define request parameters.
String spreadsheetId = "16W56LWqt6wDaYAU5xNdTWCdaY_gkuQyl4CE1lPpUui4";
String range = "Class Data!G163:I";
SpreadsheetsResource.ValuesResource.GetRequest request =
service.Spreadsheets.Values.Get(spreadsheetId, range);
// Prints the names and majors of students in a sample spreadsheet:
// https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/edit
ValueRange response = request.Execute();
IList<IList<Object>> values = response.Values;
/*
if (values != null && values.Count > 0)
{
Console.WriteLine("Name, Major");
foreach (var row in values)
{
// Print columns A and E, which correspond to indices 0 and 4.
Console.WriteLine("{0}, {1}", row[0], row[4]);
}
}
else
{
Console.WriteLine("No data found.");
}
Console.Read();
*/
}
}
}
I have modified it from the quickstart given by Google in a way that I thought it made sense but I still get in the end the same error:
There is no argument given that corresponds to the required formal parameter 'args' of 'GoogleAPI.Sheets(string[])'
as the user "David L" wrote in the comments:
As a general rule of thumb, if you do not use an argument, remove it. C# helps enforce this paradigm by throwing a compiler error if your method expects an argument and you do not provide one, which is exactly what is happening here.
It was my bad as I was under the impression of the total opposite during an API implementation. I would like to always target a clean code as a result and keeping stuff that I will not use was my bad. Thank you David!

PowerBI App-Only-Auth Embedding Issue w/ pbiClients.Reports.GetReportInGroup

I am trying to embed a Power BI report to a custom asp.net application. I have followed Microsoft's developer guidance, but I am hitting some odd issues that are not documented very well on the web.
Here is my current code:
using System;
using System.Configuration;
using System.Threading.Tasks;
using Microsoft.Rest;
using Microsoft.PowerBI.Api;
using Microsoft.PowerBI.Api.Models;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using System.Collections.Generic;
using Microsoft.Identity;
using System.Web;
using System.Security.Cryptography.X509Certificates;
namespace AppOnlyAuthPBI.Models
{
public class PBIEmbeddedManager
{
private static string resourceUriPowerBi = "https://analysis.windows.net/powerbi/api";
private static string urlPowerBiRestApiRoot = "https://api.powerbi.com/";
const string aadRootAuthorizationEndpoint = "https://login.windows.net/";
static readonly string tenantId = ConfigurationManager.AppSettings["tenant-id"];
static readonly string aadTenantAuthorizationEndpoint = aadRootAuthorizationEndpoint +
tenantId + "/";
private static string applicationId = ConfigurationManager.AppSettings["application-id"];
private static string applicationSecret = ConfigurationManager.AppSettings["application-secret"];
private static string workspaceId = ConfigurationManager.AppSettings["app-workspace-id"];
private static string reportId = ConfigurationManager.AppSettings["report-id"];
static string GetAccessToken()
{
var authContext = new AuthenticationContext(aadTenantAuthorizationEndpoint);
var clientCredential = new ClientCredential(applicationId, applicationSecret);
return authContext.AcquireTokenAsync(resourceUriPowerBi, clientCredential).Result.AccessToken;
}
private static PowerBIClient GetPowerBiClient()
{
var tokenCredentials = new TokenCredentials(GetAccessToken(), "Bearer");
return new PowerBIClient(new Uri(urlPowerBiRestApiRoot), tokenCredentials);
}
public static async Task<ReportEmbeddingData> GetReportEmbeddingData()
{
PowerBIClient pbiClient = GetPowerBiClient();
var report = await pbiClient.Reports.GetReportInGroupAsync(workspaceId, reportId);
var embedUrl = report.EmbedUrl;
var reportName = report.Name;
GenerateTokenRequest generateTokenRequestParameters = new GenerateTokenRequest(accessLevel: "view");
string embedToken =
(await pbiClient.Reports.GenerateTokenInGroupAsync(workspaceId,
report.Id,
generateTokenRequestParameters)).Token;
return new ReportEmbeddingData
{
reportId = reportId,
reportName = reportName,
embedUrl = embedUrl,
accessToken = embedToken
};
}
}
}
I am having issues ReportEmbeddingData() method.
var report = await pbiClient.Reports.GetReportInGroupAsync(workspaceId, reportId);
Here I am getting two errors, both stating cannot convert string to System.Guid. So I tried to parse them like so...
Guid.Parse(workspaceId)
Guid.Parse(reportId)
But, doing this then causes another error to appear which has no information surrounding it on the web...
string embedToken =
(await pbiClient.Reports.GenerateTokenInGroupAsync(workspaceId,
report.Id,
generateTokenRequestParameters)).Token;
I get an error on Reports.GenerateTokenInGroupAsync saying the following: "CS1929 - 'IReportsOperations' does not contain a definition for for 'GenerateTokenInGroupAsync' and the best extension method overload 'IDashboardOperationExtensions, guid, guid, GenerateTokenPermissions, CancellationToken' requires a receiver type of 'IDashboardsOperation'
To me it seems like I am missing a nuGet package, but I have verified this and everything is working as intended there and I have the required using statements applied as well.
Has anyone encountered this or does anyone know how to correct this? It seems really odd to me that Microsoft is recommending this code and I am hitting an error, leading me to believe that I am the one making the mistake but it is alluding me.
Thank you~
Use GenerateTokenInGroupWithHttpMessagesAsync()

Get List of AWS S3 Directory Name from .net core application

I am just stuck with aws s3 on my .net core mvc application. I just simply need to input bucket name of s3 then return all of directory name list in this bucket but this simple task i didn't found anywhere on internet. I already tried few solution provided by AWS forum but problem is this absolutely not works at all. Bellow i have provided my controller code also forum link. Actually the issue they told is Amazon.S3.IO and S3DirectoryInfo namespace was removed from .net core so i am failed to follow them as they advised there. Any one can fix my code bellow which will give a list of bucket directory in .net core application?
I am using two nuget package-
AWSSDK.Core and AWSSDK.S3
Forum Link - Amazon.S3.IO not supported in .Net Core anymore?
Controller:
using Amazon;
using Amazon.S3;
using Amazon.S3.Model;
public IActionResult Media()
{
string bucketName = "domain33.com";
AmazonS3Client s3Client = new AmazonS3Client("Access_Key_ID", "Secret_Access_Key", RegionEndpoint.USEast1);
var getResponse = s3Client.ListBucketsAsync(new GetObjectRequest
{
BucketName = bucketName
});
var x = getResponse;
return View();
}
You could try using the ListObjectsV2Async method on IAmazonS3 to retrieve a list of all of the existing objects in the bucket based on the AWS's example. Their code is below in case the link dies:
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: MIT-0 (For details, see https://github.com/awsdocs/amazon-s3-developer-guide/blob/master/LICENSE-SAMPLECODE.)
using Amazon.S3;
using Amazon.S3.Model;
using System;
using System.Threading.Tasks;
namespace Amazon.DocSamples.S3
{
class ListObjectsTest
{
private const string bucketName = "*** bucket name ***";
// Specify your bucket region (an example region is shown).
private static readonly RegionEndpoint bucketRegion = RegionEndpoint.USWest2;
private static IAmazonS3 client;
public static void Main()
{
client = new AmazonS3Client(bucketRegion);
ListingObjectsAsync().Wait();
}
static async Task ListingObjectsAsync()
{
try
{
ListObjectsV2Request request = new ListObjectsV2Request
{
BucketName = bucketName,
MaxKeys = 10
};
ListObjectsV2Response response;
do
{
response = await client.ListObjectsV2Async(request);
// Process the response.
foreach (S3Object entry in response.S3Objects)
{
Console.WriteLine("key = {0} size = {1}",
entry.Key, entry.Size);
}
Console.WriteLine("Next Continuation Token: {0}", response.NextContinuationToken);
request.ContinuationToken = response.NextContinuationToken;
} while (response.IsTruncated);
}
catch (AmazonS3Exception amazonS3Exception)
{
Console.WriteLine("S3 error occurred. Exception: " + amazonS3Exception.ToString());
Console.ReadKey();
}
catch (Exception e)
{
Console.WriteLine("Exception: " + e.ToString());
Console.ReadKey();
}
}
}
}
Based on that sample, you could do further processing or add the keys to a list of strings for subsequent processing, instead of just writing it the console as their example code does. For instance, you could add each key to a list, and then process that list to calculate the distinct "directories".

SQLite not storing/retrieving database

I've got a Windows 10 UWP application written in C#. I'm using SQLite to store my data locally. The issue I'm experiencing is that the file is never saved and/or retrieved using this code. It should work, but I can't find out what's wrong.
dbExists always evaluates to false, so what am I missing here?
private SQLiteConnection localConn;
private string dbPath = Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, "myDatabase.db");
public async void DBInit()
{
bool dbExists = false;
try
{
var store = await ApplicationData.Current.LocalFolder.GetFileAsync(dbPath);
dbExists = true;
}
catch { dbExists = false; }
if (!dbExists)
{
using (localConn = new SQLiteConnection(new SQLitePlatformWinRT(), dbPath))
{
// Create table
localConn.CreateTable<MyTable>();
}
}
else // CURRENTLY NOT FIRING!!
{}
}
Please consider using below code to create and access database file:
StorageFile notesFile = await storageFolder.CreateFileAsync(dbPath, CreationCollisionOption.OpenIfExists);
This will create new file if it does not exists and retrieve it when it is already created.
Please check my blog article to see more about UWP Data Storage:
https://mobileprogrammerblog.wordpress.com/2016/05/23/universal-windows-10-apps-data-storage/
I think you're missing this important piece of code:
SQLiteConnection.CreateFile("mydatabase.sqlite");
Do that first, then create a connection instance referencing the (now) created file.
Also, I'd suggest that you name the db with the .sqlite extension, so that the rest of the team and incoming devs, when then look at the db file artifact, can immediately tell that this is an sqlite database.
EDIT:
The method is a static method. So you would use it like this...
using System.Data.SQLite;
namespace sqlite_sample
{
class Program
{
static void Main(string[] args)
{
SQLiteConnection.CreateFile("sample.db");
}
}
}
The following will not work:
var conn = SQLiteConnection(...);
conn.CreateFile(dbPath); //<-- static methods can't be invoked at the instance level...

Submit C# MapReduce Job Windows Azure HDInsight - Response status code does not indicate success: 500 (Server Error)

I'm trying to submit a MapReduce job to HDInsight cluster. In my job I didn't write reduce portion because I don't want to reduce anything. All I want to do is to parse the each filename and append the values to every line in the file. So that I will have all the data needed inside the file.
My code is
using Microsoft.Hadoop.MapReduce;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GetMetaDataFromFileName
{
class Program
{
static void Main(string[] args)
{
var hadoop = connectAzure();
//Temp Workaround to Env Variables
Environment.SetEnvironmentVariable("HADOOP_HOME", #"c:\hadoop");
Environment.SetEnvironmentVariable("Java_HOME", #"c:\hadoop\jvm");
var result = hadoop.MapReduceJob.ExecuteJob<MetaDataGetterJob>();
}
static IHadoop connectAzure()
{
//TODO: Update credentials and other information
return Hadoop.Connect(
new Uri("https://sampleclustername.azurehdinsight.net//"),
"admin",
"Hadoop",
"password",
"blobstoragename.blob.core.windows.net", //Storage Account that Log files exists
"AccessKeySample", //Storage Account Access Key
"logs", //Container Name
true
);
}
//Hadoop Mapper
public class MetaDataGetter : MapperBase
{
public override void Map(string inputLine, MapperContext context)
{
try
{
//Get the meta data from name of the file
string[] _fileMetaData = context.InputFilename.Split('_');
string _PublicIP = _fileMetaData[0].Trim();
string _PhysicalAdapterMAC = _fileMetaData[1].Trim();
string _BootID = _fileMetaData[2].Trim();
string _ServerUploadTime = _fileMetaData[3].Trim();
string _LogType = _fileMetaData[4].Trim();
string _MachineUpTime = _fileMetaData[5].Trim();
//Generate CSV portion
string _RowHeader = string.Format("{0},{1},{2},{3},{4},{5},", _PublicIP, _PhysicalAdapterMAC, _BootID, _ServerUploadTime, _LogType, _MachineUpTime);
//TODO: Append _RowHeader to every row in the file.
context.EmitLine(_RowHeader + inputLine);
}
catch(ArgumentException ex)
{
return;
}
}
}
//Hadoop Job Definition
public class MetaDataGetterJob : HadoopJob<MetaDataGetter>
{
public override HadoopJobConfiguration Configure(ExecutorContext context)
{
//Initiate the job config
HadoopJobConfiguration config = new HadoopJobConfiguration();
config.InputPath = "asv://logs#sample.blob.core.windows.net/Input";
config.OutputFolder = "asv://logs#sample.blob.core.windows.net/Output";
config.DeleteOutputFolder = true;
return config;
}
}
}
}
Usually what do you thing the reason of 500 (Server Error) ? Am I suppling to wrong credentials ? Actually I didn't really understand the difference between Username and HadoopUser parameters in Hadoop.Connect method ?
Thank you,
I had approximately same issue in the past (was unable to submit hive job to the cluster with BadGateway response). I have contacted the support team and in my case the problem was in memory leakage at the head node, what means that the problem was not at client's side and it seems to be inherited hadoop problem.
I've solved that stuff by redeploying the cluster.
Have you tried to submit other jobs (simple ones)? If so, than I suggest to have a contact with azure support team or just redeploy the cluster if it's not painful for you.

Categories