I am sending token in metadata from the client side
Channel channel = new Channel("127.0.0.1:50051", ChannelCredentials.Insecure);
ItemQuery item = new ItemQuery() { Id = "abc" };
var client = new MyService.MyServiceClient(channel);
Metadata data = new Metadata
{
{ "token", "Bearer xhrttt" }
};
var reply = client.GetItem(item, data);
But not able to find a way to fetch it in server side, Any help is appreciated
below is an example of how my server-side code looks(i tried certain other ways also)
public override Task<ItemResponse> GetItem(ItemQuery request , ServerCallContext context)
{
try
{
var a = context.RequestHeaders["token"]; // not working
ItemResponse itmRes = new ItemResponse();
if (request.Id == "foo")
{
itmRes.Items.Add(new Item() { Id = "foo", Name = "foobar" });
}
return Task.FromResult(itmRes);
}
catch(Exception ex)
{
Console.WriteLine(ex.ToString());
}
return null;
}
Below is the code to fetch metadata in c#
Metadata.Entry metadataEntry = context.RequestHeaders.FirstOrDefault(m =>
String.Equals(m.Key, "token", StringComparison.Ordinal));
if (metadataEntry.Equals(default(Metadata.Entry)) || metadataEntry.Value == null)
{
return null;
}
Console.WriteLine("Token value is {0}", metadataEntry.Value);
for more details refer https://csharp.hotexamples.com/examples/Grpc.Core/ServerCallContext/-/php-servercallcontext-class-examples.html
Based on this tutorial, this and this, getting and setting metadata can be summarized:
GreeterService.cs (GrpcGreeter.csproj)
public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
{
context.WriteResponseHeadersAsync(
new Metadata() { { "server_header", "nice to see you too" } });
context.ResponseTrailers.Add(
new Metadata.Entry("server_trailer", "see you later") { });
string? client_header = context.RequestHeaders.GetValue("client_header");
return Task.FromResult(new HelloReply
{
Message = $"i got your header, {request.Name}. it reads: {client_header}"
});
}
Program.cs (GrpcGreeterClient.csproj)
// The port number must match the port of the gRPC server.
using var channel = GrpcChannel.ForAddress("https://localhost:7143");
Greeter.GreeterClient client = new Greeter.GreeterClient(channel);
var call = client.SayHelloAsync(
new HelloRequest { Name = "GreeterClient" },
new Metadata() { { "client_header", "hey there" } });
Metadata headers = await call.ResponseHeadersAsync;
Console.WriteLine($"Server Header: {headers.GetValue("server_header")}");
HelloReply rsp = await call.ResponseAsync;
Console.WriteLine($"Server Response: {rsp.Message}");
Metadata trailers = call.GetTrailers();
string? myTrailer = trailers.GetValue("server_trailer");
Console.WriteLine($"Server Trailers: {myTrailer}");
Output:
Server Header: nice to see you too
Server Response: i got your header, GreeterClient. it reads: hey there
Server Trailers: see you later
Related
I struggle with understanding how does LSP client-side works. I mean I think I understand the theory of communication (JSON-RPC/LSP Protocol basics) but I struggle with existing libraries that are used for this for VS Code and I think trying to rewrite it is kinda pointless, especially client-side where I do not feel proficient at all
All examples I see provide a path to the server, so the LSP client can start it
it makes sense, but I'd rather avoid it during development, I'd want to have the server aopen in debugging mode and just start VS Code
I tried to start with basic of basic server implementation (C#)
public class Server
{
private JsonRpc RPC { get; set; }
public async Task Start()
{
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.Console()
.CreateLogger();
var pipeName = "LSP_Pipe";
var writerPipe = new NamedPipeClientStream(pipeName);
var readerPipe = new NamedPipeClientStream(pipeName);
await writerPipe.ConnectAsync(10_000);
await readerPipe.ConnectAsync(10_000);
Log.Information("RPC Listening");
RPC = new JsonRpc(writerPipe, readerPipe, this);
RPC.StartListening();
this.RPC.Disconnected += RPC_Disconnected;
await Task.Delay(-1);
}
private void RPC_Disconnected(object sender, JsonRpcDisconnectedEventArgs e)
{
Log.Information("Disconnected");
}
[JsonRpcMethod(RPCMethods.InitializeName)]
public object Initialize(JToken arg)
{
Log.Information("Initialization");
var serializer = new JsonSerializer()
{
ContractResolver = new ResourceOperationKindContractResolver()
};
var param = arg.ToObject<InitializeParams>();
var clientCapabilities = param?.Capabilities;
var capabilities = new ServerCapabilities
{
TextDocumentSync = new TextDocumentSyncOptions(),
CompletionProvider = new CompletionOptions(),
SignatureHelpProvider = new SignatureHelpOptions(),
ExecuteCommandProvider = new ExecuteCommandOptions(),
DocumentRangeFormattingProvider = false,
};
capabilities.TextDocumentSync.Change = TextDocumentSyncKind.Incremental;
capabilities.TextDocumentSync.OpenClose = true;
capabilities.TextDocumentSync.Save = new SaveOptions { IncludeText = true };
capabilities.CodeActionProvider = clientCapabilities?.Workspace?.ApplyEdit ?? true;
capabilities.DefinitionProvider = true;
capabilities.ReferencesProvider = true;
capabilities.DocumentSymbolProvider = true;
capabilities.WorkspaceSymbolProvider = false;
capabilities.RenameProvider = true;
capabilities.HoverProvider = true;
capabilities.DocumentHighlightProvider = true;
return new InitializeResult { Capabilities = capabilities };
}
}
but I'm unable to setup client with those vscode-languageclient/node libraries even to get Log.Information("Initialization"); part
How can I provide the way they communicate - e.g name of named pipe? or just HTTP posts?
I'm not proficent in js / node development at all, so sorry for every foolish question
I've seen mature/production grade C# Language Server implementations but I'm overwhelmed just by their builders, there's sooo much stuff happening, sop that's why I'd want to write server from scratch, but for client use existing libs
var server = await LanguageServer.From(
options =>
options
.WithInput(Console.OpenStandardInput())
.WithOutput(Console.OpenStandardOutput())
.ConfigureLogging(
x => x
.AddSerilog(Log.Logger)
.AddLanguageProtocolLogging()
.SetMinimumLevel(LogLevel.Debug)
)
.WithHandler<TextDocumentHandler>()
.WithHandler<DidChangeWatchedFilesHandler>()
.WithHandler<FoldingRangeHandler>()
.WithHandler<MyWorkspaceSymbolsHandler>()
.WithHandler<MyDocumentSymbolHandler>()
.WithHandler<SemanticTokensHandler>()
.WithServices(x => x.AddLogging(b => b.SetMinimumLevel(LogLevel.Trace)))
.WithServices(
services => {
services.AddSingleton(
provider => {
var loggerFactory = provider.GetService<ILoggerFactory>();
var logger = loggerFactory.CreateLogger<Foo>();
logger.LogInformation("Configuring");
return new Foo(logger);
}
);
services.AddSingleton(
new ConfigurationItem {
Section = "typescript",
}
).AddSingleton(
new ConfigurationItem {
Section = "terminal",
}
);
}
)
.OnInitialize(
async (server, request, token) => {
var manager = server.WorkDoneManager.For(
request, new WorkDoneProgressBegin {
Title = "Server is starting...",
Percentage = 10,
}
);
workDone = manager;
await Task.Delay(2000);
manager.OnNext(
new WorkDoneProgressReport {
Percentage = 20,
Message = "loading in progress"
}
);
}
)
.OnInitialized(
async (server, request, response, token) => {
workDone.OnNext(
new WorkDoneProgressReport {
Percentage = 40,
Message = "loading almost done",
}
);
await Task.Delay(2000);
workDone.OnNext(
new WorkDoneProgressReport {
Message = "loading done",
Percentage = 100,
}
);
workDone.OnCompleted();
}
)
.OnStarted(
async (languageServer, token) => {
using var manager = await languageServer.WorkDoneManager.Create(new WorkDoneProgressBegin { Title = "Doing some work..." });
manager.OnNext(new WorkDoneProgressReport { Message = "doing things..." });
await Task.Delay(10000);
manager.OnNext(new WorkDoneProgressReport { Message = "doing things... 1234" });
await Task.Delay(10000);
manager.OnNext(new WorkDoneProgressReport { Message = "doing things... 56789" });
var logger = languageServer.Services.GetService<ILogger<Foo>>();
var configuration = await languageServer.Configuration.GetConfiguration(
new ConfigurationItem {
Section = "typescript",
}, new ConfigurationItem {
Section = "terminal",
}
);
var baseConfig = new JObject();
foreach (var config in languageServer.Configuration.AsEnumerable())
{
baseConfig.Add(config.Key, config.Value);
}
logger.LogInformation("Base Config: {Config}", baseConfig);
var scopedConfig = new JObject();
foreach (var config in configuration.AsEnumerable())
{
scopedConfig.Add(config.Key, config.Value);
}
logger.LogInformation("Scoped Config: {Config}", scopedConfig);
}
)
);
Thanks in advance
Trying to make use of the AndroidPublisherService from Play Developer API Client.
I can list active tracks and the releases in those tracks, but when I try to upload a new build there seems to be no way of attaching the authentication already made previously to read data.
I've authenticated using var googleCredentials = GoogleCredential.FromStream(keyDataStream) .CreateWithUser(serviceUsername); where serviceUsername is the email for my service account.
private static void Execute(string packageName, string aabfile, string credfile, string serviceUsername)
{
var credentialsFilename = credfile;
if (string.IsNullOrWhiteSpace(credentialsFilename))
{
// Check env. var
credentialsFilename =
Environment.GetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS",
EnvironmentVariableTarget.Process);
}
Console.WriteLine($"Using credentials {credfile} with package {packageName} for aab file {aabfile}");
var keyDataStream = File.OpenRead(credentialsFilename);
var googleCredentials = GoogleCredential.FromStream(keyDataStream)
.CreateWithUser(serviceUsername);
var credentials = googleCredentials.UnderlyingCredential as ServiceAccountCredential;
var service = new AndroidPublisherService();
var edit = service.Edits.Insert(new AppEdit { ExpiryTimeSeconds = "3600" }, packageName);
edit.Credential = credentials;
var activeEditSession = edit.Execute();
Console.WriteLine($"Edits started with id {activeEditSession.Id}");
var tracksList = service.Edits.Tracks.List(packageName, activeEditSession.Id);
tracksList.Credential = credentials;
var tracksResponse = tracksList.Execute();
foreach (var track in tracksResponse.Tracks)
{
Console.WriteLine($"Track: {track.TrackValue}");
Console.WriteLine("Releases: ");
foreach (var rel in track.Releases)
Console.WriteLine($"{rel.Name} version: {rel.VersionCodes.FirstOrDefault()} - Status: {rel.Status}");
}
using var fileStream = File.OpenRead(aabfile);
var upload = service.Edits.Bundles.Upload(packageName, activeEditSession.Id, fileStream, "application/octet-stream");
var uploadProgress = upload.Upload();
if (uploadProgress == null || uploadProgress.Exception != null)
{
Console.WriteLine($"Failed to upload. Error: {uploadProgress?.Exception}");
return;
}
Console.WriteLine($"Upload {uploadProgress.Status}");
var tracksUpdate = service.Edits.Tracks.Update(new Track
{
Releases = new List<TrackRelease>(new[]
{
new TrackRelease
{
Name = "Roswell - Grenis Dev Test",
Status = "completed",
VersionCodes = new List<long?>(new[] {(long?) upload?.ResponseBody?.VersionCode})
}
})
}, packageName, activeEditSession.Id, "internal");
tracksUpdate.Credential = credentials;
var trackResult = tracksUpdate.Execute();
Console.WriteLine($"Track {trackResult?.TrackValue}");
var commitResult = service.Edits.Commit(packageName, activeEditSession.Id);
Console.WriteLine($"{commitResult.EditId} has been committed");
}
And as the code points out, all action objects such as tracksList.Credential = credentials; can be given the credentials generated from the service account.
BUT the actual upload action var upload = service.Edits.Bundles.Upload(packageName, activeEditSession.Id, fileStream, "application/octet-stream"); does not expose a .Credential object, and it always fails with:
The service androidpublisher has thrown an exception: Google.GoogleApiException: Google.Apis.Requests.RequestError
Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project. [401]
Errors [
Message[Login Required.] Location[Authorization - header] Reason[required] Domain[global]
]
at Google.Apis.Upload.ResumableUpload`1.InitiateSessionAsync(CancellationToken cancellationToken)
at Google.Apis.Upload.ResumableUpload.UploadAsync(CancellationToken cancellationToken)
So, how would I go about providing the actual Upload action with the given credentials here?
Managed to figure this out during the day, I was missing one call to CreateScoped() when creating the GoogleCredential object as well as a call to InitiateSession() on the upload object.
var googleCredentials = GoogleCredential.FromStream(keyDataStream)
.CreateWithUser(serviceUsername)
.CreateScoped(AndroidPublisherService.Scope.Androidpublisher);
Once that was done I could then get a valid oauth token by calling
var googleCredentials = GoogleCredential.FromStream(keyDataStream)
.CreateWithUser(serviceUsername)
.CreateScoped(AndroidPublisherService.Scope.Androidpublisher);
var credentials = googleCredentials.UnderlyingCredential as ServiceAccountCredential;
var oauthToken = credentials?.GetAccessTokenForRequestAsync(AndroidPublisherService.Scope.Androidpublisher).Result;
And I can now use that oauth token in the upload request:
upload.OauthToken = oauthToken;
_ = await upload.InitiateSessionAsync();
var uploadProgress = await upload.UploadAsync();
if (uploadProgress == null || uploadProgress.Exception != null)
{
Console.WriteLine($"Failed to upload. Error: {uploadProgress?.Exception}");
return;
}
The full code example for successfully uploading a new aab file to google play store internal test track thus looks something like this:
private async Task UploadGooglePlayRelease(string fileToUpload, string changeLogFile, string serviceUsername, string packageName)
{
var serviceAccountFile = ResolveServiceAccountCertificateInfoFile();
if (!serviceAccountFile.Exists)
throw new ApplicationException($"Failed to find the service account certificate file. {serviceAccountFile.FullName}");
var keyDataStream = File.OpenRead(serviceAccountFile.FullName);
var googleCredentials = GoogleCredential.FromStream(keyDataStream)
.CreateWithUser(serviceUsername)
.CreateScoped(AndroidPublisherService.Scope.Androidpublisher);
var credentials = googleCredentials.UnderlyingCredential as ServiceAccountCredential;
var oauthToken = credentials?.GetAccessTokenForRequestAsync(AndroidPublisherService.Scope.Androidpublisher).Result;
var service = new AndroidPublisherService();
var edit = service.Edits.Insert(new AppEdit { ExpiryTimeSeconds = "3600" }, packageName);
edit.Credential = credentials;
var activeEditSession = await edit.ExecuteAsync();
_logger.LogInformation($"Edits started with id {activeEditSession.Id}");
var tracksList = service.Edits.Tracks.List(packageName, activeEditSession.Id);
tracksList.Credential = credentials;
var tracksResponse = await tracksList.ExecuteAsync();
foreach (var track in tracksResponse.Tracks)
{
_logger.LogInformation($"Track: {track.TrackValue}");
_logger.LogInformation("Releases: ");
foreach (var rel in track.Releases)
_logger.LogInformation($"{rel.Name} version: {rel.VersionCodes.FirstOrDefault()} - Status: {rel.Status}");
}
var fileStream = File.OpenRead(fileToUpload);
var upload = service.Edits.Bundles.Upload(packageName, activeEditSession.Id, fileStream, "application/octet-stream");
upload.OauthToken = oauthToken;
_ = await upload.InitiateSessionAsync();
var uploadProgress = await upload.UploadAsync();
if (uploadProgress == null || uploadProgress.Exception != null)
{
Console.WriteLine($"Failed to upload. Error: {uploadProgress?.Exception}");
return;
}
_logger.LogInformation($"Upload {uploadProgress.Status}");
var releaseNotes = await File.ReadAllTextAsync(changeLogFile);
var tracksUpdate = service.Edits.Tracks.Update(new Track
{
Releases = new List<TrackRelease>(new[]
{
new TrackRelease
{
Name = $"{upload?.ResponseBody?.VersionCode}",
Status = "completed",
InAppUpdatePriority = 5,
CountryTargeting = new CountryTargeting { IncludeRestOfWorld = true },
ReleaseNotes = new List<LocalizedText>(new []{ new LocalizedText { Language = "en-US", Text = releaseNotes } }),
VersionCodes = new List<long?>(new[] {(long?) upload?.ResponseBody?.VersionCode})
}
})
}, packageName, activeEditSession.Id, "internal");
tracksUpdate.Credential = credentials;
var trackResult = await tracksUpdate.ExecuteAsync();
_logger.LogInformation($"Track {trackResult?.TrackValue}");
var commitResult = service.Edits.Commit(packageName, activeEditSession.Id);
commitResult.Credential = credentials;
await commitResult.ExecuteAsync();
_logger.LogInformation($"{commitResult.EditId} has been committed");
}
I am writing to you because i got error during using the AutoML API from google.cloud.
Documentation website:
https://cloud.google.com/translate/automl/docs/predict#automl_translate_predict-csharp
public async Task<IActionResult> UploadToTranslate(IFormFile excelFile)
{
//rest of code...
string credential_path = #"xxxx.json";
System.Environment.SetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS", credential_path);
var client = PredictionServiceClient.Create();
var modelName = ModelName.Format(_config.GetValue<string>("ValuesEnPl:projectId"), _config.GetValue<string>("ValuesEnPl:location"), _config.GetValue<string>("ValuesEnPl:modelId"));
var predictionRequest = new PredictRequest
{
Name = modelName,
Payload = new ExamplePayload
{
TextSnippet = new TextSnippet
{
Content = "Tom goes home"
},
},
};
try
{
var response = client.Predict(predictionRequest, CallSettings.FromCallTiming(CallTiming.FromDeadline(DateTime.UtcNow.AddSeconds(100))));
foreach (var payload in response.Payload)
{
Console.Write($"Translated Content: {payload.Translation.TranslatedContent.Content}");
}
}
catch (RpcException ex)
{
}
//rest of code...
}
Exception: Message = "Status(StatusCode=Unavailable, Detail=\"failed
to connect to all addresses\")"
I have trained dialogflow but i want to create an webhook API for receiving and sending an response.
I have created the intent with Enabled the webhook to get response in it.
Any help would be appreciated.....
[HttpPost]
public dynamic DialogAction([FromBody] WebhookRequest dialogflowRequest)
{
var intentName = dialogflowRequest.QueryResult.Intent.DisplayName;
var actualQuestion = dialogflowRequest.QueryResult.QueryText;
var testAnswer = $"Dialogflow Request for intent {intentName} and question {actualQuestion}";
var parameters = dialogflowRequest.QueryResult.Parameters;
var dialogflowResponse = new WebhookResponse
{
FulfillmentText = testAnswer,
FulfillmentMessages =
{ new Intent.Types.Message
{ SimpleResponses = new Intent.Types.Message.Types.SimpleResponses
{ SimpleResponses_ =
{ new Intent.Types.Message.Types.SimpleResponse
{
DisplayText = testAnswer,
TextToSpeech = testAnswer,
}
}
}
}
}
};
var jsonResponse = dialogflowResponse.ToString();
return new ContentResult { Content = jsonResponse, ContentType = "application/json" }; ;
//return "Connecteds";
}
I've read along the way that Salesforce (I'm extremely new to this 3rd party platform) has a FUEL SDK which one can use instead of the version (using HttpClient -- REST instead of SOAP).
Please correct me if using FUEL SDK is the only way to go about requesting Salesforce's endpoints. Currently I am attempting to hit ExactTargets's API endpoints using HttpClient. These are the tutorials I've been basing my code off of:
https://developer.salesforce.com/docs/atlas.en-us.mc-apis.meta/mc-apis/messageDefinitionSends.htm
https://developer.salesforce.com/docs/atlas.en-us.mc-getting-started.meta/mc-getting-started/get-access-token.htm
Wanted Result:
To be able to request a Triggered Send email based off a template inside of ExactTarget.
Problem:
The Salesforce endpoint continuously returns a 404. I am able to receive the authorization token successfully. The GetAccessToken method is omitted for brevity
https://www.exacttargetapis.com/messaging/v1/messageDefinitionSends/key:MyExternalKey/send
I do not understand why the 2nd POST request to //www.exacttargetapis.com/..... returns a 404 but the authorization works. This leads me to believe that I do not have to use the FUEL SDK to accomplish triggering a welcome email.
Code:
private const string requestTokenUrl = "https://auth.exacttargetapis.com/v1/requestToken";
private const string messagingSendUrl = "https://www.exacttargetapis.com/messaging/v1/messageDefinitionSends";
private string exactTargetClientId = ConfigurationManager.AppSettings["ExactTargetClientId"];
private string exactTargetClientSecret = ConfigurationManager.AppSettings["ExactTargetClientSecret"];
private string TriggerEmail(User model, string dbName)
{
var etExternalKeyAppSetting = ConfigurationManager.AppSettings.AllKeys.FirstOrDefault(x => x.Equals(dbName));
if (etExternalKeyAppSetting != null)
{
string etExternalKey = ConfigurationManager.AppSettings[etExternalKeyAppSetting];
HttpClient client = new HttpClient
{
BaseAddress = new Uri(string.Format(#"{0}/key:{1}/send", messagingSendUrl, etExternalKey)),
DefaultRequestHeaders =
{
Authorization = new AuthenticationHeaderValue("Bearer", this.GetAccessToken())
}
};
try
{
var postData = this.CreateExactTargetPostData(model.Email, etExternalKey);
var response = client.PostAsync(client.BaseAddress
, new StringContent(JsonConvert.SerializeObject(postData).ToString()
, Encoding.UTF8
, "application/json")).Result;
// get triggered email response
if (response.IsSuccessStatusCode)
{
dynamic result = JsonConvert.DeserializeObject(response.Content.ReadAsStringAsync().Result);
}
}
catch (Exception ex)
{
string message = ex.Message;
}
}
return "testing";
}
private object CreateExactTargetPostData(string email, string extKey)
{
var fromData = new
{
Address = ConfigurationManager.AppSettings["AwsSenderEmail"],
Name = "Test"
};
var subscriberAttributes = new { };
var contactAttributes = new
{
SubscriberAttributes = subscriberAttributes
};
var toData = new
{
Address = email,
//SubscriberKey = extKey,
//ContactAttributes = contactAttributes
};
var postData = new
{
From = fromData,
To = toData
};
return postData;
}
I have also tried using Advanced REST Client using the following:
URL:
https://www.exacttargetapis.com/messaging/v1/messageDefinitionSends/key:MyExternalKey/send
POST
Raw Headers:
Content-Type: application/json
Authorization: Bearer XXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Raw Payload:
{
"From": {
"Address": "code#exacttarget.com",
"Name": "Code#"
},
"To": {
"Address": "example#example.com",
"SubscriberKey": "example#example.com",
"ContactAttributes": {
"SubscriberAttributes": {
"Region": "West",
"City": "Indianapolis",
"State": "IN"
}
}
},
"OPTIONS": {
"RequestType": "ASYNC"
}
}
Issue was my App in the AppCenter was pointing to the incorrect login for MarketingCloud =(