I'm trying to run the Echo sample between two machines on my local network. The sample uses the netTcpRelayBinding and it works fine if I run both the service and the client on the same machine.
When I first compiled the services and put it on my other machine, a Windows 2003 Server with no dev tools installed. It wouldn't run because it didn't know what netTcpRelayBinding was in the app.config. So I moved the config to code only and the service started. I confirmed this with the Service Bus Explorer.
I then tried to connect with my dev machine (through VS2010) but it won't work. I have tried to change stuff both on the service and the client, trying all the combination of settings I can think of, but nothing.
I mostly get one of two errors on the client:
"ContractDescription 'IEchoContract' has zero operations; a contract must have at least one operation."
or
"there was no endpoint listening that could accept the message".
This is the server code, my change is between the custom comments.
// create the service URI based on the service namespace
Uri address = ServiceBusEnvironment.CreateServiceUri("sb", serviceNamespace, "EchoService");
// create the credentials object for the endpoint
TransportClientEndpointBehavior sharedSecretServiceBusCredential = new TransportClientEndpointBehavior();
sharedSecretServiceBusCredential.CredentialType = TransportClientCredentialType.SharedSecret;
sharedSecretServiceBusCredential.Credentials.SharedSecret.IssuerName = issuerName;
sharedSecretServiceBusCredential.Credentials.SharedSecret.IssuerSecret = issuerSecret;
// create the service host reading the configuration
ServiceHost host = new ServiceHost(typeof(EchoService), address);
// custom
host.AddServiceEndpoint(
typeof(IEchoContract),
new NetTcpRelayBinding(),
"EchoService" );
// custom end
// create the ServiceRegistrySettings behavior for the endpoint
IEndpointBehavior serviceRegistrySettings = new ServiceRegistrySettings(DiscoveryType.Public);
// add the Service Bus credentials to all endpoints specified in configuration
foreach (ServiceEndpoint endpoint in host.Description.Endpoints)
{
endpoint.Behaviors.Add(serviceRegistrySettings);
endpoint.Behaviors.Add(sharedSecretServiceBusCredential);
}
// open the service
host.Open();
This is the client code, my current change is between the custom comments:
// create the service URI based on the service namespace
Uri serviceUri = ServiceBusEnvironment.CreateServiceUri("sb", serviceNamespace, "EchoService");
// create the credentials object for the endpoint
TransportClientEndpointBehavior sharedSecretServiceBusCredential = new TransportClientEndpointBehavior();
sharedSecretServiceBusCredential.CredentialType = TransportClientCredentialType.SharedSecret;
sharedSecretServiceBusCredential.Credentials.SharedSecret.IssuerName = issuerName;
sharedSecretServiceBusCredential.Credentials.SharedSecret.IssuerSecret = issuerSecret;
// create the channel factory loading the configuration
//ChannelFactory<IEchoChannel> channelFactory = new ChannelFactory<IEchoChannel>("RelayEndpoint", new EndpointAddress(serviceUri));
// custom
ServiceEndpoint endpoint = new ServiceEndpoint(new ContractDescription("IEchoContract", "Microsoft.ServiceBus.Samples"), new NetTcpRelayBinding(EndToEndSecurityMode.Transport, RelayClientAuthenticationType.None), new EndpointAddress(serviceUri));
ChannelFactory<IEchoChannel> channelFactory = new ChannelFactory<IEchoChannel>(endpoint);
// custom end
// apply the Service Bus credentials
channelFactory.Endpoint.Behaviors.Add(sharedSecretServiceBusCredential);
// create and open the client channel
IEchoChannel channel = channelFactory.CreateChannel();
channel.Open();
My app.config files are cleared of the settings. I haven't touched any other files.
It's because the namespace of the labs is different from the "old" appfabric. I dont know how to get it working right now. Just pretty much "Microsoft" again...
I got the same issue and when I debugged it I found that the issuerKey coming from the config is "yourkey". These values are stored in the Azure project itself, ServiceConfiguration.cscfg file. You need to place some real values there and it should be OK.
I meet same issue then, I figue out, this example need your own service bus.
So create a service bus in your portal, then copy the issuer key's value to issure secret.
Related
It's not a good sign when the method I'm asking about, GetUserDelegationKey, yields zero search results on SO. Good luck, me.
I have a C# console app, .Net framework 4.8, using Azure.Storage.Blobs and Azure.Identity that will run on customer servers and access Azure blob storage to hold some stuff. I'm doing all of this with the library, not rolling my own REST. Built with VS2019, testing on Win10.
The plan is to use a single Azure storage account that I own, and create one Container per customer project with per-customer credentials that permit them only their own container. Projects never ever talk to each other.
I could set up credentials in the Azure portal by hand, but I am stubbornly trying to do this in software, where a simple project-management app connects as the project app's service principal (which I defined in Azure AD), creates the container, then creates the shared access signatures with a limited lifetime.
The storage account name / container name / access signature would then be configured on the customer server.
I'm having a terrible time.
Note: this is using the newer BlobClient mechanisms, not the older CloudBlob stuff. Dunno if that matters.
This is all documented here at Microsoft, and following even the simple example gets me the same failure.
using System;
using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Models;
using Azure.Identity;
namespace Azure.Test
{
class Program
{
static void Main(string[] args)
{
var serviceClient = new BlobServiceClient(
new Uri("https://stevestorageacct.blob.core.windows.net"),
new DefaultAzureCredential(true)); // true=pop up login dlg
/*BOOM*/ UserDelegationKey key = serviceClient.GetUserDelegationKey(
DateTimeOffset.UtcNow,
DateTimeOffset.UtcNow.AddDays(30));
// use the key to create the signatures
}
}
}
Even though this program couldn't be simpler, it fails every time with an XML error calling GetUserDelegationKey
Unhandled Exception: Azure.RequestFailedException: The value for one of the XML nodes is not in the correct format.
RequestId:c9b7d324-401e-0127-4a4c-1fe6ce000000
Time:2020-05-01T00:06:21.3544489Z
Status: 400 (The value for one of the XML nodes is not in the correct format.)
ErrorCode: InvalidXmlNodeValue
The XML being sent is supposed to be super simple, I think just the start/end dates for validity, but I have no idea how to get to it to inspect, and http is forbidden for this kind of call, so no Wireshark.
It also fails the same way when I use my application's service principal:
static void Main(string[] args)
{
var tokenCredential = new ClientSecretCredential(
"xxxx-xxxx-xxxx-xxxxx", // tenant ID
"yyyy-yyyy-yyyy-yyyyy, // application ID
"**************"); // client secret
var serviceClient = new BlobServiceClient(
new Uri("https://stevestorageacct.blob.core.windows.net"),
tokenCredential);
UserDelegationKey key = serviceClient.GetUserDelegationKey(
DateTimeOffset.UtcNow,
DateTimeOffset.UtcNow.AddDays(30));
// ALSO: boom
I'm really at a loss.
I suppose I could try rolling my own REST and playing with it that way, but it doesn't feel like this should be necessary: this kind of error feels like a bug even if I'm doing something wrong. XML nodes?
Also open to entirely different ways of approaching this problem if they are superior, but would like to at least find out why this is failing.
I've had some issues with this also. The first things to try is removing the start time (pass null) or setting it ~15 minutes in the past. This is to avoid clock skew between the requesting pc and azure servers.
The second thing to verify is that the user that you are using has the "Storage Blob Data Contributor" role on the storage account. I had to grant it at the storage account level in the end otherwise it just refused to work for me. However in your use case it might be that you need to grant it at the container level to allow you to have one container per client.
Hope this helps.
I am trying to access Azure Key Vault from my Azure App Service. I followed the steps outlined on this documentation: https://learn.microsoft.com/en-us/azure/key-vault/managed-identity (turned on system assigned identity for the app service, updated the access policy of the key vault to include the app with Get,List secret permissions).
However, when I run the web application, it is not able to get the secret from the key vault and my web service hits the following error:
502 - Web server received an invalid response while acting as a gateway or proxy server.
There is a problem with the page you are looking for, and it cannot be displayed. When the Web server (while acting as a gateway or proxy) contacted the upstream content server, it received an invalid response from the content server.
This is what my code looks like:
AzureServiceTokenProvider azureServiceTokenProvider = new AzureServiceTokenProvider();
KeyVaultClient keyVaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
var secret = keyVaultClient.GetSecretAsync(KeyVaultUrl);
authenticationKey = secret.Result.Value;
The service gets stuck on the secret.Result.Value line. Is there something else I need to do?
This is much easier with the new package, like Azure.Security.KeyVault.Secrets. Together with Azure.Identity, you can just pass a DefaultAzureCredential like in our samples.
var client = new SecretClient(
new Uri("https://myvault.vault.azure.net"),
new DefaultAzureCredential());
KeyVaultSecret secret = await client.GetSecretAsync("secret-name");
string authenticationKey = secret.Value;
The DefaultAzureCredential is optimized to work for managed identity, service principals from the environment, and interactive logins to support the same code running both in production and on developer machines. The new libraries are also faster with fewer allocations, and have much better diagnostics - defaulted to on when using Azure Application Monitor.
They target netstandard2.0 so should be compatible with the older packages these replace. Would you be able to upgrade? We're only making critical fixes for the older packages, and recommending people upgrade to Azure.* packages intead of the older Microosft.Azure.* packages.
As for the problem itself, it's hard to say without knowing when you're calling this in your application. During startup? What version of .NET? What are you using for your ASP.NET application framework?
While it's probably not the cause of the problem, it's hard to ignore that you're calling an async method synchronously, which can also cause problems. If you're in an async method, you should write your code like so:
var secret = await keyVaultClient.GetSecretAsync(KeyVaultUrl);
authenticationKey = secret.Value;
If not, call:
var secret = keyVaultClient.GetSecretAsnc(KeyVaultUrl).GetAwaiter().GetResult();
This is not recommended, though. In the new packages I mentioned above, we have both sync and async versions that are either sync or async all the way through the call stack and safer to use. Generally, though, you should use async calls - especially for network traffic like accessing Key Vault because, depending on what thread you call it, it can hang your UI.
When you test in local:
Add your vs signed account into azure keyvault. Go to keyvault> Access policy> add your account with get secret permmission.
When you publish to azure:
1.Enable webapp MSI.
2.Go to keyvault> Access policy> add your webapp's service principal with get secret permission.
The code:
AzureServiceTokenProvider azureServiceTokenProvider = new AzureServiceTokenProvider();
KeyVaultClient keyVaultClient = new KeyVaultClient(new Microsoft.Azure.KeyVault.KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
var secret = keyVaultClient.GetSecretAsync("https://yourkevaultname.vault.azure.net/secrets/secretname/437d301daxxxxxx");
var authenticationKey = secret.Result.Value;
ViewBag.Message = authenticationKey.ToString();
I'm trying to create a new Azure Mobile Service, however when trying to call a Custom API it generates the following error in the logs of the service.
An error occurred creating push for user scripts:
azure.notificationHubService could not be created. HubName:
"servicenamehub" ConnectionString
"Endpoint=sb://servicenamehub-ns.servicebus.windows.net/;
SharedAccessKeyName=DefaultFullSharedAccessSignature;
SharedAccessKey={accesskey};EntityPath=servicenamehub": Error from
create-Error: Invalid connection string setting key "entitypath".
The error only seems to generate when making an API call, not when making a call on a table.
The MS_NotificationHubConnectionString is where this connection string is stored, however it was auto generated along with the service hub and isn't editable in the service configuration.
The EntityPath key doesn't appear in the MS_NotificationHubConnectionString of any of my older services. The Mobile Service has a JavaScript back end.
How do I prevent this error or remove the EntityPath key from the connection string?
Currently, here is a workaround: we login Kudu console site of the Mobile Service backend, modify MS_NotificationHubConnectionString in the script which will create notification hub service directly in source code.
login in Kudu console site, whose url should be https://<your_mobile_service_name>.scm.azure-mobile.net/DebugConsole
In the file system list in the page, enter to the path D:\home\site\wwwroot\node_modules\azure-mobile-services\runtime\push, edit the file pushadapter.js
Add following code to the start of the function PushAdapter in this script around line 22:
var string = options.MS_NotificationHubConnectionString;
var index = string.indexOf('EntityPath');
options.MS_NotificationHubConnectionString = index>0?string.slice(0,string.indexOf('EntityPath')-1):string;
Any further concern, please feel free to let me know.
I have implemented Azure Mobile App and Xamarin.Forms Client application. I want user to login using facebook from Phone and also want to fetch user's profile data. For this I have implemented the additional call/method into API controller in Azure Mobile App. I have followed steps and put the code as per your article but somehow get following error message when I run the Mobile App on localhost or trying to publish
Multiple types were found that match the controller named 'Home'. This can happen if the route that services this request ('') found multiple controllers defined with the same name but differing namespaces, which is not supported. The request for 'Home' has found the following matching controllers:
Microsoft.Azure.Mobile.Server.Controllers.HomeController Microsoft.WindowsAzure.Mobile.Service.Controllers.HomeController
I understand this is related config settings. I have following code in place
HttpConfiguration config = new HttpConfiguration();
new MobileAppConfiguration()
.UseDefaultConfiguration()
.ApplyTo(config);
app.UseWebApi(config);
app.UseAppServiceAuthentication(new AppServiceAuthenticationOptions
{
SigningKey = ConfigurationManager.AppSettings["SigningKey"],
ValidAudiences = new[] { ConfigurationManager.AppSettings["ValidAudience"] },
ValidIssuers = new[] { ConfigurationManager.AppSettings["ValidIssuer"] },
TokenHandler = config.GetAppServiceTokenHandler()
});
If I remove the default configuration from above then exception message go away but in that case I don't see the app getting hosted properly i.e. it is showing blank page in browser instead of ready page shown once app is hosted properly.
What steps you followed, could you please show the link?
That exception is routing-related and very common, and can be fixed - for example, by use of areas. A lot of manuals are available, for example, here - http://blog.falafel.com/duplicate-controller-names-aspnet-mvc-areas/ .
You have added two different SDKs - one for Azure Mobile Services v1 and the other for Azure App Service Mobile Apps (which can be considered v2). You need to remove the reference to the older one.
Use the appropriate SDK for the service you are using, and delete the other one.
Using the new Windows Azure SDK for .NET, I want to get a list of all virtual machines.
Piecing together the early documentation, here's what I came up with:
// This is a custom cert I made locally. I uploaded it to Azure's Management Certificates and added it to my local computer's cert store, see screenshot below.
X509Certificate2 myCustomCert = await this.GetAzureCert();
var credentials = new CertificateCloudCredentials(mySubscriptionId, myCustomCert);
using (var cloudServiceClient = CloudContext.Clients.CreateCloudServiceManagementClient(credentials))
{
credentials.InitializeServiceClient(cloudServiceClient); // Is this required? The next call fails either way.
// This line fails with exception: "The server failed to authenticate the request. Verify that the certificate is valid and is associated with this subscription."
var services = await cloudServiceClient.CloudServices.ListAsync(CancellationToken.None);
}
My first thought was the cert was bad, but I am able to successfully call the Azure REST API using my custom certificate. As you can see below, it is properly added to the Azure Management Certificates and associated with my subscription:
What am I doing wrong?
Here's another option - rather than upload a cert, try pulling your management cert out of your publishsettings file and using the X509Certificate's constructor that takes a byte[]. Then, pass that parameter the result of a call to Convert.FromBase64String, passing it the string representation of your management certificate from your publishsettings file.
Also, take a look at the Compute management client rather than the Cloud Service Management client. There are more features specific to the compute stack in that client at this time. The code below is a demonstration of such an approach. Note, my _subscriptionId and _managementCert fields are both strings, and I just hard-code them to the values from my publishsettings file as I described above.
public async static void ListVms()
{
using (var client = new ComputeManagementClient(
new CertificateCloudCredentials(_subscriptionId,
new X509Certificate2(Convert.FromBase64String(_managementCert)))
))
{
var result = await client.HostedServices.ListAsync();
result.ToList().ForEach(x => Console.WriteLine(x.ServiceName));
}
}
There's a parameterless ListAsync method that's an extension method. Try importing the Microsoft.WindowsAzure.Management namespace (or the Microsoft.WindowsAzure.Management.Compute namespace). Once you see the parameterless ListAsync method you should be good. I'll also mock up some code to resemble what you're trying to accomplish and offer up a more comprehensive answer by the end of the day.