I have an azure function below, I have webhook trigger when i mention my bot in my chat. It triggers the azure Function but it sends infinite messages back to my room and I have to stop the entire function.
#r "Newtonsoft.Json"
using System.Net; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Primitives; using Newtonsoft.Json;
public static async Task<object> Run(HttpRequestMessage req, TraceWriter log) {
string jsonContent = await req.Content.ReadAsStringAsync();
var dto = JsonConvert.DeserializeObject<RootObject>(jsonContent);
string callerName = dto.data.personEmail;
using (var httpClient = new HttpClient())
{
using (var request = new HttpRequestMessage(new HttpMethod("POST"), "https://****************"))
{
request.Headers.TryAddWithoutValidation("Cache-Control", "no-cache");
request.Headers.TryAddWithoutValidation("Authorization", "Bearer *****************************************************");
request.Headers.TryAddWithoutValidation("Postman-Token", "**********************");
var multipartContent = new MultipartFormDataContent();
multipartContent.Add(new StringContent(callerName), "markdown");
multipartContent.Add(new StringContent("***********************************"), "roomId");
request.Content = multipartContent;
var response = await httpClient.SendAsync(request);
}
}
return req.CreateResponse(HttpStatusCode.OK);
}
public class Data {
public string id { get; set; }
public string roomId { get; set; }
public string roomType { get; set; }
public string personId { get; set; }
public string personEmail { get; set; }
public List<string> mentionedPeople { get; set; }
public DateTime created { get; set; }
}
public class RootObject {
public Data data { get; set; }
}
You need to bind it as an HttpTrigger. Currently, your function is just running without any type of triggering.
There are many types.
HttpTrigger
TimerTrigger
BlobTrigger
QueueTrigger
EventHubTrigger
SendGridTrigger
Many others, mentioned below in Microsoft example URL
Package for HttpTrigger: https://www.nuget.org/packages/Microsoft.Azure.WebJobs.Extensions.Http
You may also need:
https://www.nuget.org/packages/Microsoft.Azure.WebJobs
Example(from https://learn.microsoft.com/en-us/azure/azure-functions/functions-bindings-http-webhook):
public static async Task<HttpResponseMessage> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]HttpRequestMessage req,
TraceWriter log)
{
log.Info("C# HTTP trigger function processed a request.");
// parse query parameter
string name = req.GetQueryNameValuePairs()
.FirstOrDefault(q => string.Compare(q.Key, "name", true) == 0)
.Value;
// Get request body
dynamic data = await req.Content.ReadAsAsync<object>();
// Set name to query string or body data
name = name ?? data?.name;
return name == null
? req.CreateResponse(HttpStatusCode.BadRequest, "Please pass a name on the query string or in the request body")
: req.CreateResponse(HttpStatusCode.OK, "Hello " + name);
}
Related
I have tried to submit an object from client app to an API which contains some data and a file, but I failed to do so.
Here is the code:
(1) The model:
public class ABC
{
public int Id { get; set; }
public string Image { get; set; }
public string Name { get; set; }
[NotMapped]
public IFormFile File { get; set; }
}
(2) The client app controller
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(ABC aBC)
{
using (var httpClient = new HttpClient())
{
StringContent content = new StringContent(JsonConvert.SerializeObject(aBC), Encoding.UTF8, "application/json");
using (var response = httpClient.PostAsync(BaseURLManager.BaseUrl + "ABCs", content))
{
var apiResponse = response.Result.Content.ReadAsStringAsync();
aBC = JsonConvert.DeserializeObject<ABC>(apiResponse.Result);
}
}
return View(aBC);
}
(3) The API controller
// POST: api/ABCs
[HttpPost]
public async Task<ActionResult<ABC>> PostABC([FromForm] ABC aBC)
{
_context.ABC.Add(aBC);
await _context.SaveChangesAsync();
return CreatedAtAction("GetABC", new { id = aBC.Id }, aBC);
}
Could any one provide me a working code, I am using ASP.NET Core 5.
Thank you in advance
Since you use the FromForm attribute inside the api method, you should send request in formdata instead of json format.
More details, you could refer to below codes:
var client = new HttpClient
{
BaseAddress = new("https://localhost:7105/api/")
};
var path = $"{_hostEnvironment.ContentRootPath}test.json";
var stream = System.IO.File.OpenRead(path);
var request = new HttpRequestMessage(HttpMethod.Post, "PostABC");
var content = new MultipartFormDataContent
{
// file
{ new StreamContent(stream), "File", "test.json" },
// payload
{ new StringContent("1"), "Id" },
{ new StringContent("bbbb"), "Image" },
{ new StringContent("ccc"), "Name" }
};
request.Content = content;
var re = client.SendAsync(request).Result;
Result:
this is my api endpoint
[HttpPost("stream")]
public async Task<IActionResult> UploadStreamAsync(FileUploadRequest request)
{
// my code
}
this is the request model
FileUploadRequest
{
public string FileName { get; set; }
public string FileType { get; set; }
public string Path { get; set; }
public object Content { get; set; } //this can be either a json, a byte[] or a Stream
}
when i create a post request in Postman for testing a Stream content parameter, how do i send that file with my json request?
this is my headers tab in Postman
this is my request body
when i send the request i get an error response:
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.13",
"title": "Unsupported Media Type",
"status": 415,
"traceId": "00-bea9f28c0c2fd7e79ad8e296011e985a-177cdd0dcded6de1-00"
}
I've tried setting a form-body parameter of type file and upload it like that, and then set the other params i need in my request, each param in a different row.
i also tried to set one param as the file and one param as the json with the other params except for content (see img link above), also didn't work.
what am i doing wrong?
can this be done like this at all?
This is my model:
public class FileUploadRequest
{
public string FileName { get; set; }
//public object Content { get; set; }
public IFormFile Content { get; set; }
}
This is my api:
public class HomeController : Controller
{
[HttpPost("stream")]
public string UploadStream(FileUploadRequest request)
{
return "asdf";
}
}
Then when I call it :
With postman:
I set the body like this, and I didn't modify the headers.
Try using this method:
[STAThread]
public async Task UploadStreamAsync(FileUploadRequest FileUpload){
using (HttpClient Request = new HttpClient())
{
// If you need to add a header for Path or FileType: Request.DefaultRequestHeaders.Add(HEADER, VALUE);
var Uri = new Uri(/*YOUR POST URL*/);
using (var Stream = File.OpenRead())
{
var multipartContent = new MultipartFormDataContent();
multipartContent.Add(
new StreamContent(Stream),
FileUploaded.FileName, // What the content is going to be named when uploaded
FileUploaded.Content /*Sets the value*/);
HttpRequestMessage Req = new HttpRequestMessage(HttpMethod.Post, Uri);
Req.Content = multipartContent;
var Response = await Request.SendAsync(Req);
var Body = Response.Content; // Response
}
}
}
By posting a request to my database, I only get string values .For some reason, the floating values don't get to the DB.
Model
public DateTime ? Date {get;set; }
public double latitud { get; set; }
public double longitud { get; set; }
public string Name { get; set; }
Model Request = Model;
Request.latitud=location.Latitude;
Request.longitud=location.Longitude;
Request.Date=DateTime.Now;
Request.Name=Name;
Service:
public async Task<string> Post(Model Request)
{
var response = new ServiceResponse<string>();
using (var httpClient = new HttpClient())
{
InitClient(httpClient);
httpClient.DefaultRequestHeaders.TryAddWithoutValidation(
"Content-Type", "application/json");
var result = await httpClient.PostAsync(API_URL,
new
StringContent(JsonConvert.SerializeObject(Request),
System.Text.Encoding.UTF8, "application/json"));
Debug.WriteLine("post results : " + result.Content);
}
}
return response;
}
Date, Name is successfully posted anytime I called the service,
However, none of the doubles values does. NOTE- I am 100% sure that all the values are been sent in the object Request.
I am trying to create a C# HTTP-triggered Function from the Azure portal (Embedded Analytics with Power BI). I follow the post of Taygan ( https://www.taygan.co/blog/2018/05/14/embedded-analytics-with-power-bi ) and using the ref for System.Web.Extensions but it throw:
Metadata file 'System.Web.Extensions' could not be found
This is the code:
#r "System.Web.Extensions"
using System.Configuration;
using System.Net;
using System.Text;
using System.Web.Script.Serialization;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using Microsoft.PowerBI.Api.V2;
using Microsoft.PowerBI.Api.V2.Models;
using Microsoft.Rest;
// Static Values
static string authorityUrl = "https://login.windows.net/common/oauth2/authorize/";
static string resourceUrl = "https://analysis.windows.net/powerbi/api";
static string apiUrl = "https://api.powerbi.com/";
static string clientId = ConfigurationManager.AppSettings["PBIE_CLIENT_ID"];
static string username = ConfigurationManager.AppSettings["PBIE_USERNAME"];
static string password = ConfigurationManager.AppSettings["PBIE_PASSWORD"];
static string groupId = ConfigurationManager.AppSettings["PBIE_GROUP_ID"];
static string reportId = ConfigurationManager.AppSettings["PBIE_REPORT_ID"];
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
// Authenticate with Azure Ad > Get Access Token > Get Token Credentials
var credential = new UserPasswordCredential(username, password);
var authenticationContext = new AuthenticationContext(authorityUrl);
var authenticationResult = await authenticationContext.AcquireTokenAsync(resourceUrl, clientId, credential);
string accessToken = authenticationResult.AccessToken;
var tokenCredentials = new TokenCredentials(accessToken, "Bearer");
using (var client = new PowerBIClient(new Uri(apiUrl), tokenCredentials))
{
// Embed URL
Report report = client.Reports.GetReportInGroup(groupId, reportId);
string embedUrl = report.EmbedUrl;
// Embed Token
var generateTokenRequestParameters = new GenerateTokenRequest(accessLevel: "view");
EmbedToken embedToken = client.Reports.GenerateTokenInGroup(groupId, reportId, generateTokenRequestParameters);
// JSON Response
EmbedContent data = new EmbedContent();
data.EmbedToken = embedToken.Token;
data.EmbedUrl = embedUrl;
data.ReportId = reportId;
JavaScriptSerializer js = new JavaScriptSerializer();
string jsonp = "callback(" + js.Serialize(data) + ");";
// Return Response
return new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent(jsonp, Encoding.UTF8, "application/json")
};
}
}
public class EmbedContent
{
public string EmbedToken { get; set; }
public string EmbedUrl { get; set; }
public string ReportId { get; set; }
}
How can I fix it? Please help me, thank you.
Problem is caused by the difference of Function runtime.
The tutorial you follow creates function on ~1 runtime where code targets at .NET Framework , while the one you create is on ~2 runtime which runs on .NET Core env. When we create a new Function app its runtime is set to ~2 by default now.
Solution is to set FUNCTIONS_EXTENSION_VERSION to ~1 in Application settings on portal.
To achieve that in ~2 runtime, create a httptrigger in ~2 and replace the sample code with snippet below. Note you also have to add PBIE_TENANT_ID in Application settings with value get from Azure Active Directory> Properties>Directory ID.
#r "Newtonsoft.Json"
using System.Net;
using System.Text;
using Newtonsoft.Json;
static string resourceUrl = "https://analysis.windows.net/powerbi/api";
static string clientId = Environment.GetEnvironmentVariable("PBIE_CLIENT_ID");
static string username = Environment.GetEnvironmentVariable("PBIE_USERNAME");
static string password = Environment.GetEnvironmentVariable("PBIE_PASSWORD");
static string groupId = Environment.GetEnvironmentVariable("PBIE_GROUP_ID");
static string reportId = Environment.GetEnvironmentVariable("PBIE_REPORT_ID");
static string tenantId = Environment.GetEnvironmentVariable("PBIE_TENANT_ID");
static string tokenEndpoint = $"https://login.microsoftonline.com/{tenantId}/oauth2/token";
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, ILogger log)
{
// Get access token
HttpClient authclient = new HttpClient();
log.LogInformation(resourceUrl);
log.LogInformation(tokenEndpoint);
var authContent = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("grant_type", "password"),
new KeyValuePair<string, string>("username", username),
new KeyValuePair<string, string>("password", password),
new KeyValuePair<string, string>("client_id", clientId),
new KeyValuePair<string, string>("resource", resourceUrl)
});
var accessToken = await authclient.PostAsync(tokenEndpoint, authContent).ContinueWith<string>((response) =>
{
log.LogInformation(response.Result.StatusCode.ToString());
log.LogInformation(response.Result.ReasonPhrase.ToString());
log.LogInformation(response.Result.Content.ReadAsStringAsync().Result);
AzureAdTokenResponse tokenRes =
JsonConvert.DeserializeObject<AzureAdTokenResponse>(response.Result.Content.ReadAsStringAsync().Result);
return tokenRes?.AccessToken;
});
// Get PowerBi report url and embed token
HttpClient powerBiClient = new HttpClient();
powerBiClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {accessToken}");
log.LogInformation(accessToken);
var embedUrl =
await powerBiClient.GetAsync($"https://api.powerbi.com/v1.0/myorg/groups/{groupId}/reports/{reportId}")
.ContinueWith<string>((response) =>
{
log.LogInformation(response.Result.StatusCode.ToString());
log.LogInformation(response.Result.ReasonPhrase.ToString());
PowerBiReport report =
JsonConvert.DeserializeObject<PowerBiReport>(response.Result.Content.ReadAsStringAsync().Result);
return report?.EmbedUrl;
});
var tokenContent = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("accessLevel", "view")
});
var embedToken = await powerBiClient.PostAsync($"https://api.powerbi.com/v1.0/myorg/groups/{groupId}/reports/{reportId}/GenerateToken", tokenContent)
.ContinueWith<string>((response) =>
{
log.LogInformation(response.Result.StatusCode.ToString());
log.LogInformation(response.Result.ReasonPhrase.ToString());
PowerBiEmbedToken powerBiEmbedToken =
JsonConvert.DeserializeObject<PowerBiEmbedToken>(response.Result.Content.ReadAsStringAsync().Result);
return powerBiEmbedToken?.Token;
});
// JSON Response
EmbedContent data = new EmbedContent
{
EmbedToken = embedToken,
EmbedUrl = embedUrl,
ReportId = reportId
};
string jsonp = "callback(" + JsonConvert.SerializeObject(data) + ");";
// Return Response
return new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent(jsonp, Encoding.UTF8, "application/json")
};
}
public class AzureAdTokenResponse
{
[JsonProperty("access_token")]
public string AccessToken { get; set; }
}
public class PowerBiReport
{
[JsonProperty(PropertyName = "id")]
public string Id { get; set; }
[JsonProperty(PropertyName = "name")]
public string Name { get; set; }
[JsonProperty(PropertyName = "webUrl")]
public string WebUrl { get; set; }
[JsonProperty(PropertyName = "embedUrl")]
public string EmbedUrl { get; set; }
[JsonProperty(PropertyName = "datasetId")]
public string DatasetId { get; set; }
}
public class PowerBiEmbedToken
{
[JsonProperty(PropertyName = "token")]
public string Token { get; set; }
[JsonProperty(PropertyName = "tokenId")]
public string TokenId { get; set; }
[JsonProperty(PropertyName = "expiration")]
public DateTime? Expiration { get; set; }
}
public class EmbedContent
{
public string EmbedToken { get; set; }
public string EmbedUrl { get; set; }
public string ReportId { get; set; }
}
So I create an HttpPut method in an ASP.NET web api.
[Route("api/Account/Save")]
[HttpPut]
public IHttpActionResult SaveAccount(Account acc) {
// do stuff
}
I pass in an instant of the Account class.
class Account
{
public int AccountID { get; set; }
public string AccountName { get; set; }
}
Now I want to call this from a console application. I am trying to do this but it's not working. It's not throwing any exception either.
var acc = new Account() { AccountID = 1234, AccountName = "zzzzP" };
string json = JsonConvert.SerializeObject(acc);
HttpContent content = new StringContent(json);
response = await client.PutAsync("api/Account/Save", content);
Json returned:
"{\"AccountID\":1234,\"AccountName\":\"zzzzP\"}"
You probably want something like this
static async Task PutAccount()
{
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri("http://yourWebSite.com");
var acc = new Account() { AccountID = 1234, AccountName = "zzzzP" };
string json = JsonConvert.SerializeObject(acc);
using (HttpResponseMessage response = await client.PutAsync("api/Account/Save", new StringContent(json)))
{
return response.EnsureSuccessStatusCode();
}
}
}