I have some services that require rather complex objects. Every service uses almost the same base object but it needs to be extended for each service.
A simple example:
The Standard Object would be something like:
ContextObject {
params {
Device {
Name: "MyMobileDevice",
ID: 123455691919238
}
}
}
and for my service I need to add some properties under params,
something like:
ContextObject {
params {
Device {
Name: "MyMobileDevice",
ID: 123455691919238
},
requested_employee_id: 112929
}
}
I tried to get this by using JObject and got it working so far but now I cant find a proper example on how to send this object to my server using HttpClient.
Edit:
Here is my full JObject which all Requests need:
public static JObject DefaultContext (string ServiceMethod) {
var Context = new JObject();
Context["version"] = "1.1";
Context["method"] = ServiceMethod;
Context["params"] = JObject.FromObject( new {
Context = JObject.FromObject( new {
User = App.UserSettings.USERNAME,
Password = App.UserSettings.PASSWORD,
SerialNumber = "1234567890", // TODO: use generated id
Locale = "de-DE",
Timestamp = DateTime.Now.ToString("yyyy-MM-ddTHH\\:mm\\:ss.fffzzz"),
Device = JObject.FromObject( new {
DeviceType = "phone",
ProductType = "D6603", // TODO: Get from Device-Info
screen = JObject.FromObject( new {
Density = "xxhdpi", // TODO: Get from Device-Info
resolution = JObject.FromObject( new {
Height = "1920", // TODO: Get from Device-Info
Width = "1080" // TODO: Get from Device-Info
})
}),
version = JObject.FromObject( new {
AppVersion = "myAppVersion", // TODO: Get App-Information LayoutVersion = "1.0"
} )
})
})
});
return mobileContext;
}
For my Requests I need to add parameters under the "params"-Node. Which works with:
mobileContext["params"]["mynewparameter"] = "FOO";
Now I wanted to send this JObject via System.Net.Http-Client to my server with something like this:
var client = new HttpClient ();
client.BaseAddress = new Uri (App.UserSettings.HOST + ":" + App.UserSettings.PORT + App.UserSettings.TYPE);
client.Timeout = 3000;
var context = MyContext.DefaultContext (ServiceMethods.CUSTOMER_LIST_METHOD);
context ["params"] ["myrequestparam"] = "FOO";
var jsonString = JsonConvert.SerializeObject (context);
var responseData = await client.Get???????
Is my general approach correct? How would you do it? Is there a sample on how to handle such dynamic stuff?
I couldn't find a example on how to use httpclient correctly with the Newtonsoft.JSON-Library how far am I from actually working code?
Related
I have stored an api key to invoke APigateway in secret manager. And I am trying to fetch that secret from cdk and attach to the rule's header parameter as given below
var secret = Amazon.CDK.AWS.SecretsManager.Secret.FromSecretAttributes(this, "SCMId", new Amazon.CDK.AWS.SecretsManager.SecretAttributes
{
SecretCompleteArn = apikeyArn
});
var apikey = secret.SecretValueFromJson("ApiKey").Resolve;
var httpParameters = new Amazon.CDK.AWS.Events.CfnRule.HttpParametersProperty { HeaderParameters = new Dictionary<string, string> { { "x-api-key", apikey.ToString() } } };
Then the event target with above http parameter
var eventRule = new Amazon.CDK.AWS.Events.CfnRule(this, ruleId, new Amazon.CDK.AWS.Events.CfnRuleProps
{
EventBusName = busName,
Name = ruleName,
Description = description,
EventPattern = eventPattern,
Targets = new[]
{
new Amazon.CDK.AWS.Events.CfnRule.TargetProperty
{
Id = id,
Arn = apiArn,
HttpParameters = httpParameters,
RoleArn = roleArn,
}
}
});
Still the api key is not working and I am getting 403 error when that particular event trying to invoke api.
Here I have created my project on the standard .NET library to GET/POST invoices. But as I want to email the invoice to which it's being created on that name. Here is my sample code below to create invoice.
public async Task<ActionResult> Create(string Name, string LineDescription, string LineQuantity, string LineUnitAmount, string LineAccountCode)
{
var xeroToken = TokenUtilities.GetStoredToken();
var utcTimeNow = DateTime.UtcNow;
var serviceProvider = new ServiceCollection().AddHttpClient().BuildServiceProvider();
var httpClientFactory = serviceProvider.GetService<IHttpClientFactory>();
XeroConfiguration XeroConfig = new XeroConfiguration
{
ClientId = ConfigurationManager.AppSettings["XeroClientId"],
ClientSecret = ConfigurationManager.AppSettings["XeroClientSecret"],
CallbackUri = new Uri(ConfigurationManager.AppSettings["XeroCallbackUri"]),
Scope = ConfigurationManager.AppSettings["XeroScope"],
State = ConfigurationManager.AppSettings["XeroState"]
};
if (utcTimeNow > xeroToken.ExpiresAtUtc)
{
var client = new XeroClient(XeroConfig, httpClientFactory);
xeroToken = (XeroOAuth2Token)await client.RefreshAccessTokenAsync(xeroToken);
TokenUtilities.StoreToken(xeroToken);
}
string accessToken = xeroToken.AccessToken;
string xeroTenantId = xeroToken.Tenants[0].TenantId.ToString();
//string xeroTenantId = xeroToken.Tenants[1].TenantId.ToString();
var contact = new Contact();
contact.Name = Name;
var line = new LineItem()
{
Description = LineDescription,
Quantity = decimal.Parse(LineQuantity),
UnitAmount = decimal.Parse(LineUnitAmount),
AccountCode = LineAccountCode
};
var lines = new List<LineItem>() { line };
//var lines = new List<LineItem>();
//for (int j = 0;j < 5;j++)
//{
// lines.Add(line);
//}
var invoice = new Invoice()
{
Type = Invoice.TypeEnum.ACCREC,
Contact = contact,
Date = DateTime.Today,
DueDate = DateTime.Today.AddDays(30),
LineItems = lines
};
var invoiceList = new List<Invoice>();
invoiceList.Add(invoice);
var invoices = new Invoices();
invoices._Invoices = invoiceList;
var AccountingApi = new AccountingApi();
var response = await AccountingApi.CreateInvoicesAsync(accessToken, xeroTenantId, invoices);
RequestEmpty _request = new RequestEmpty();
//trying this method to send email to specified invoice....
//var test = await AccountingApi.EmailInvoiceAsync(accessToken, xeroTenantId, Guid.NewGuid(), null);
var updatedUTC = response._Invoices[0].UpdatedDateUTC;
return RedirectToAction("Index", "InvoiceSync");
}
Now as I learned that Xero allows sending email to that specified invoice, here is a link which I learned.
https://developer.xero.com/documentation/api/invoices#email
But as try to find method in the .NET standard library for Xero I stumble upon this method.
var test = await AccountingApi.EmailInvoiceAsync(accessToken, xeroTenantId, Guid.NewGuid(), null);
How can I use this method to send email to a specified invoice ..?
It throws me an error regarding Cannot assign void to an implicitly-typed variable.
There is another method also in this library.
var test2 = await AccountingApi.EmailInvoiceAsyncWithHttpInfo(accessToken, xeroTenantId, Guid.NewGuid(), null);
As Guid.NewGuid() i have used is for only testing will add created GUID when I understand how these two methods operate.
Update 1:
Here is the method second method i used.
await AccountingApi.EmailInvoiceAsyncWithHttpInfo(accessToken, xeroTenantId, Guid.NewGuid(), null)
Update 2:
Here is the code i used.
public async Task EmailInvoiceTest(string accessToken,string xeroTenantId,Guid invoiceID, RequestEmpty requestEmpty)
{
var AccountingApi = new AccountingApi();
await AccountingApi.EmailInvoiceAsync(accessToken, xeroTenantId, invoiceID, requestEmpty).ConfigureAwait(false);
}
The return type of method EmailInvoiceAsync seems to be Task with return type void. If you await the task, there is no return type which could be assigned to a variable. Remove the variable assignment and pass a valid argument for parameter of type RequestEmpty to solve the problem.
RequestEmpty requestEmpty = new RequestEmpty();
await AccountingApi.EmailInvoiceAsync(accessToken, xeroTenantId, Guid.NewGuid(), requestEmpty);
For an example test see here
IMPORTANT: According to the documentation (see section Emailing an invoice) the invoice must be of Type ACCREC and must have a valid status for sending (SUMBITTED, AUTHORISED or PAID).
I'm trying to consume a Graphql Api from a C# client. For that I'm using the GraphQl.Net Nuget package. The problem is that, I have no idea how to set the Api Url as I don't have HttpRequest object and this results also with additional problems that I can't set the authentcation header and send the token with the request. My code looks like:
public void Post(TestGraphQl.GraphQLQuery query)
{
var inputs = query.Variables.ToInputs();
var queryToExecute = query.Query;
var result = _executer.ExecuteAsync(_ =>
{
_.Schema = _schema;
_.Query = queryToExecute;
_.OperationName = query.OperationName;
_.Inputs = inputs;
//_.ComplexityConfiguration = new ComplexityConfiguration { MaxDepth = 15 };
_.FieldMiddleware.Use<InstrumentFieldsMiddleware>();
}).Result;
var httpResult = result.Errors?.Count > 0
? HttpStatusCode.BadRequest
: HttpStatusCode.OK;
var json = _writer.Write(result);
}
And the caller looks like this:
var jObject = new Newtonsoft.Json.Linq.JObject();
jObject.Add("id", deviceId);
client.Post(new GraphQLQuery { Query = "query($id: String) { device (id: $id) { displayName, id } }", Variables = jObject });
I'm totally new to this topic and appreciate any help. Many thanks!!
This worked out for me. You will need the GraphQL.Client Package. My_class is the class for the deserialization.
var client = new GraphQLHttpClient(Api_Url, new NewtonsoftJsonSerializer());
var request = new GraphQLRequest
{
Query = {query}
};
var response = await client.SendQueryAsync<my_class>(request);
Not sure if you are still looking for it. One can always use GraphQl.Client nuget to achieve this. Sample code to consume is
var query = #"query($id: String) { device (id: $id) { displayName, id } }";
var request = new GraphQLRequest(){
Query = query,
Variables = new {id =123}
};
var graphQLClient = new GraphQLClient("http://localhost:8080/api/GraphQL");
graphQLClient.DefaultRequestHeaders.Add("Authorization", "yourtoken");
var graphQLResponse = await graphQLClient.PostAsync(request);
Console.WriteLine(graphQLResponse.Data);
So I finally figured out a way to successfully make detect intent calls and provide an input context. My question is whether or not this is the CORRECT (or best) way to do it:
(And yes, I know you can just call DetectIntent(agent, session, query) but I have to provide a input context(s) depending on the request)
var query = new QueryInput
{
Text = new TextInput
{
Text = model.Content,
LanguageCode = string.IsNullOrEmpty(model.Language) ? "en-us" : model.Language,
}
};
var commonContext = new global::Google.Cloud.Dialogflow.V2.Context
{
ContextName = new ContextName(agent, model.sessionId, "my-input-context-data"),
LifespanCount = 3,
Parameters = new Struct
{
Fields = {
{ "Source", Value.ForString(model.Source) },
{ "UserId" , Value.ForString(model.UserId.ToString())},
{ "Name" , Value.ForString(model.FirstName)}
}
}
};
var request = new DetectIntentRequest
{
SessionAsSessionName = new SessionName(agent, model.sessionId),
QueryParams = new QueryParameters
{
GeoLocation = new LatLng {Latitude = model.Latitude, Longitude = model.Longitude},
TimeZone = model.TimeZone ?? "MST"
},
QueryInput = query
};
request.QueryParams.Contexts.Add(commonContext);
// ------------
var creds = GetGoogleCredentials("myCredentials.json");
var channel = new Grpc.Core.Channel(SessionsClient.DefaultEndpoint.Host, creds.ToChannelCredentials());
var client = SessionsClient.Create(channel);
var response = client.DetectIntent(request);
channel.ShutdownAsync();
return response;
Note: I included the explicit ShutDownAsync (it's not in an async call) because I was getting some file locking issues when attempting to re-deploy the WebAPI project (and only after having executed this code).
Thanks
Chris
Updated 4/25: The most basic way I use this is to integrate the user's name into intent responses:
It can also be read from within the webhook/inline fulfillment index.js:
const name = request.body.queryResult && request.body.queryResult.outputContexts && request.body.queryResult.outputContexts[0].parameters.Name
I have a few Soap-requests that all start the same:
First request:
var client = new Conn.Team.z_proj_team_spQueryPortClient();
client.Endpoint.Address = EndPoint;
var query = new Conn.Team.z_proj_team_spQuery
{
Filter = new Conn.Team.z_proj_team_spFilter
{
param_code = projectCode
}
};
var auth = new Conn.Team.Auth { Username = _username, Password = _password };
var records = client.Query(auth, query).Records;
second request:
var client = new Conn.Task.z_proj_Task_spQueryPortClient();
client.Endpoint.Address = EndPoint;
var query = new Conn.Task.z_proj_Task_spQuery
{
Filter = new Conn.Task.z_proj_Task_spFilter
{
param_code = projectCode
}
};
var auth = new Conn.Task.Auth { Username = _username, Password = _password };
var records = client.Query(auth, query).Records;
As you can see, the code looks nearly the same, but these are completely different objects (that do not share a base class) but who use the same property-names.
Because I have about 10 of these calls, is there a good way to wrap these functions? Would you even advice to do so or would Reflection simple makes it "more evil"?
(BTW:) I am unsure what a good tag would be for my problem. Feel free to change them to better ones
Solved this the following "reflection/dynamic" way. Feel free to post a better solution if you have one.
private object Connect(Type clientType, Type queryType, Type filterType, Type authType, string code)
{
dynamic client = Activator.CreateInstance(clientType);
client.Endpoint.Address = EndPoint;
dynamic query = Activator.CreateInstance(queryType);
dynamic filter = Activator.CreateInstance(filterType);
filter.param_code = code;
query.Filter = filter;
dynamic auth = Activator.CreateInstance(authType);
auth.Username = _username;
auth.Password = _password;
return client.Query(auth, query).Records;
}