I have a well functioning Azure Function App running multiple http triggered functions that provide JSON payloads.
I am trying to call a specific function from my Blazor WASM hosted on Azure Static Web App. I have linked the Function App to the Static Web App and all functions are visible in the Static Web App.
The Function App name displayed in the Static Web Apps Functions blade is my-existing-function-appand in the name list all functions are formatted: my-existing-function-app/GetMyStuff, my-existing-function-app/SetMyStuff, etc
The original uri for the function looks like this: https://my-existing-function-app.azurewebsites.net/api/GetMyStuff?code=ASDFkt5346345ywSDGSTy45734gowjgwWERT==. Calling that endpoint delivers my data as expected.
In my Blazor App I can activate the original endpoint when debugging locally by running this line: mystuff = await Http.GetFromJsonAsync<MyStuff[]>('https://my-existing-function-app.azurewebsites.net/api/GetMyStuff?code=ASDFkt5346345ywSDGSTy45734gowjgwWERT==');
My Static Web App url looks like this: https://red-sea-123.azurestaticapps.net
I have followed the documentation found here: https://learn.microsoft.com/en-us/azure/static-web-apps/functions-bring-your-own
According to the documentation it is a bit unclear, what I should write here: mystuff = await Http.GetFromJsonAsync<MyStuff[]>(HERE)
I have tried different variations like 'api/GetMyStuff', 'my-existing-function-app/GetMyStuff' and 'my-existing-function-app/api/GetMyStuff', but none of them get access to the endpoint. It is clear from the browsers developer console, that i get some error page back.
How should I construct the HERE string in my call?
Please check if the below steps for adding the await Http GetFromJsonAsync Method in the Blazor App and helps to workaround:
According to the documentation it is a bit unclear, what I should write here: mystuff = await Http.GetFromJsonAsync<MyStuff[]>(HERE)
Here is an article contains about the calling Azure Function App from the Blazor WASM.
This is the code where you have to include your await Http GetFromJsonAsync operation in the razor app:
#page "/covidfaq"
#inject HttpClient Http
<div class="d-flex justify-content-center">
<img src="../Images/COVID_banner.jpg" alt="Image" style="width:80%; height:300px" />
</div>
<br />
<div class="d-flex justify-content-center">
<h1>Frequently asked Questions on Covid-19</h1>
</div>
<hr />
#if (questionList == null)
{
<p><em>Loading...</em></p>
}
else
{
#foreach (var question in questionList)
{
<div class="card">
<h3 class="card-header">
#question.Question
</h3>
<div class="card-body">
<p class="card-text">#question.Answer</p>
</div>
</div>
<br />
}
}
#code {
private FAQ[] questionList;
protected override async Task OnInitializedAsync()
{
questionList = await Http.GetFromJsonAsync<FAQ[]>("https://faqfunctionapp20200611160123.azurewebsites.net/api/covidFAQ");
}
public class FAQ
{
public string Id { get; set; }
public string Question { get; set; }
public string Answer { get; set; }
}
}
Inside the OnInitializedAsync method, the Azure Function app API Endpoint is hitting and the returned data stored in questionList array type variable.
Please visit the above article for more information.
Related
image of the detail view with console to see the console.log()
I'm having troubles making the Tour Of Heroes Angular tutorial work, i'm in the 6 step of the tutorial, getting the data from a server but instead of getting the data from a simulated data server i have a api with nodejs express and mysql.
The problem cames when i try to show the detail of the hero (fetching one by id), all seems to work but the information don't show on the view.
template:
<div *ngIf="hero">
<h2>{{ hero.name }} Details</h2>
<div>id: {{hero.id}}</div>
<div>
<label for="name">Hero name: </label>
<input id="name" [(ngModel)]="hero.name" placeholder="name">
</div>
<button type="button" (click)="goBack()">go back</button>
</div>
component:
ngOnInit(): void {
this.getHero();
}
getHero(){
const id = Number(this.route.snapshot.paramMap.get("id"));
this.heroService.getHero(id).subscribe(hero => {
this.hero = hero;
console.log("hero", hero)
})
}
service:
private heroesUrl = 'http://localhost:3300/api/';
constructor(private MessageService: MessageService, private http: HttpClient) {
}
private log(message: string) {
this.MessageService.add(`HeroService: ${message}`);
}
getHeroes(): Observable<Hero[]>{
this.log('HeroService: fetched heroes');
return this.http.get<Hero[]>(this.heroesUrl);
}
getHero(id: number): Observable<Hero> {
const url = `${this.heroesUrl}${id}`;
return this.http.get<Hero>(url);
}
I don't know what's the problem, im learning angular but the observable is well suscribed, in the attached image you can see in the console that at least the api is working.
you received an array with an unique element, see the [``] in console. So
Or in subscribe your write hero[0]
this.heroService.getHero(id).subscribe(hero => {
this.hero = hero[0];
})
Or in your service return the first element of the array. For this use rxjs/operator map
getHero(id: number): Observable<Hero> {
const url = `${this.heroesUrl}${id}`;
return this.http.get<Hero[]>(url).pipe(
map((res:Hero[])=>res[0])
);
}
See that although you say to Angular that getHero return an Observable<Hero> really you got an Observable<Hero[]>. Yes, when we indicate the return of a function this not make "magically" we get the result, only help us to write the code and the editor advise us about it
I am having an ASP.NET Core Razor application, where I am using the JavaScript AppInsights component for the ckient-side (configured in _Layout.cshtml) and the nuget package for the server-side.
Unfortunately, I am not able to correlate page views on the client-side to requests on the server-side. Also, the application map is not getting drawn correctly, no matter what I try. As you can see, they are "disconnected".
I have tried the following settings on the front end without luck. Any idea?
disableFetchTracking: false,
enableCorsCorrelation: true,
enableRequestHeaderTracking: true,
enableResponseHeaderTracking: true,
I figured it out. The documentation only lists XMLHttpRequest calls under the auto-collected dependency items for JavaScript.
So that implies I have to change views like this
// MySite.cshtml
#page
#model ...
#{
ViewData["Title"] = "My Site";
}
<h1>#ViewData["Title"]</h1>
<form method="post" class="mt-1">
<button class="btn btn-primary">Do something</button>
<input type="hidden" name="id" value="doSomething" />
</form>
// MySite.cshtml.cs
public class MySiteModel : PageModel
{
// ...
public void OnPost(string id)
{
// ...
}
}
To views that make use of AJAX, e.g like so
// MySite.cshtml
#page
#model ...
#{
ViewData["Title"] = "Exceptions";
}
<h1>#ViewData["Title"]</h1>
<button class="btn btn-primary" id="doSomething">Do Something</button>
#section scripts
{
<script>
$(document).click(e => {
var id = e.target.id;
if (id == "doSomething") {
$.ajax({
url: '?handler=DoSomething
});
}
});
</script>
}
// MySite.cshtml.cs
public MySiteModel : PageModel
{
...
public void OnGetDoSomething()
{
...
}
}
And now everything looks as it should
In my ASP.NET Core 3.1 web application, I allow users to upload images that are stored in local directories within the application itself. Whilst, this could be better served using blob storage on Azure, this particular project has called for them to be stored locally, so I have to work with that:
wwwroot/images/products/whatever_id/whatever_name.jpg
and
wwwroot/images/companies/whatever_id/whatever_name.jpg
When a user uploads an image, the processing of the image is handled by ImageSharp from SixLabors where the image is resized a few times for use across the platform and saved to the relative directory which is separated by the Id.
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;
The Problem
The problem I face is that, whilst this process works when I test my application locally, it doesn't work when I deploy my application to Azure and there are no errors of any kind reported back. This has left me high and dry when trying to work out what is going on.
Assumptions
Due to the nature of this issue and the location of these images, I can only assume that it's azure preventing the overwriting of images within the directories for security reasons, or perhaps it's the ImageSharp library itself.
It's important to note that, the actual creation of products and adding of images when the directories don't exist, so, a new product, works perfectly. It's only if you try to overwrite the image that it doesn't work.
Here is my code, I've removed all none essential elements, leaving on the image processing specific code.
Edit(View)
#model Products
<form asp-action="Edit" asp-controller="Products" method="POST" enctype="multipart/form-data">
<div class="card m-4">
<div class="card-header">
<h3 class="card-title">Add Product</h3>
</div>
<div class="card-body">
<div class="container-fluid">
<div class="row">
<div class="col-md-4">
<div class="form-group">
<label>Product Images</label>
<kendo-upload name="ProductImages" multiple="true" show-file-list="true">
</kendo-upload>
</div>
</div>
</div>
<div class="row">
<div class="col">
<button type="submit" class="btn btn-purple">Submit</button>
</div>
</div>
</div>
</div>
</div>
</form>
Edit(Controller)
[HttpPost]
public IActionResult Edit(Products product)
{
if (ModelState.IsValid && product != null)
{
try
{
//Process the Images
if (product.ProductImages != null)
{
ProcessImages(product, product.Id);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return RedirectToAction("Index");
}
return View();
}
ProcessImages(Stream)
private readonly int[] sizeArray = new int[] { 700, 350, 150 };
public Stream ProcessImages(Products model, int? id)
{
try
{
//Get the images and define the directory structure
var images = model.ProductImages;
var root = _env.WebRootPath;
var folderName = Path.Combine(root, "images", "products", id.ToString());
//If the ID Directory doesn't exist, create it first.
if (!Directory.Exists(folderName))
{
Directory.CreateDirectory(folderName);
}
//Interate over the images and process them
foreach (var item in images)
{
foreach (var imageSize in sizeArray)
{
string imageSizeName = "image" + imageSize + ".jpg";
string fullPath = Path.Combine(folderName, imageSizeName);
//Create the stream and process the image
using FileStream fileStream = new FileStream(fullPath, FileMode.Create);
try
{
Stream inStream = item.OpenReadStream();
using Image image = Image.Load(inStream);
int width = imageSize;
int height = 0;
var clone = image.Clone(i => i.Resize(width, height));
clone.SaveAsJpeg(fileStream);
inStream.Position = 0;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return (null);
}
As you can see, there is a size array, where the sizes we need are defined and then looped over and processed. We create the file name and save as a jpg. The height is set to 0 so that it automatically sets it when the width is defined and then the stream is reset.
Products.cs(model)
public class Products : BaseEntity
{
public string Title { get; set; }
[NotMapped]
public IFormFileCollection ProductImages { get; set; }
}
So, the question remains, why can I not overwrite my images once my application is live in Azure? Is it an Azure security concern, something simple like an ImageSharp library issue or is my application not performing this action correctly?
That code does not look correct. In ProcessImages
You're loading the image then cloning it for each size (load outside the loop)
You're not disposing of the clone after saving it to the stream.
You're always returning null.
#LazZiya is correct here though, regarding caching. Since you're reusing the same name over again, the browser will simply request the same cached image. If you add any querystring parameter in your e.g. v=[PRODUCTRECORD_LASTWRITETIME] you will get the new image.
For simplicities sake I recommend you simply upload the source image and use the ImageSharp.Web middleware to serve your resized images.
This will automatically handle source image changes and reduce storage overheads. You can host your source images on the server and the cached result in blob storage.
requests become as simple as
https://PATH_TO_IMAGE?with=[NUMBER]
I wrote asp.net razor pages web app.
On the page/form there are few controls that I want to distinct during the post.
Unfortunatly I failed to define custom handler, its always fired thruogh the default OnPost .
on the page:
<form method="post">
<button type="submit" class="btn btn-default" asp-route-data="2" asp-page-handler="custom">Start test 2</button>
</form>
in the module:
public void OnPost()
{
ViewData["confirmation"] = $"from OnPost";
}
public void OnPostcustom(string data)
{
ViewData["confirmation"] = $"from OnPostcustom";//never reach this line
}
what is my fault? according to the documentation it should be a very basic procedure.
There is a problem with the name of custom handler: handler mechanism of razor pages doesn't recognize the name if it starts with a not capital letter.
i.e OnPostcustom will never be used, while OnPostCustom will succeed
I'm developing a backend in MVC 5 for a client to update in their website. However I got across this error:
Error Image
This is the controller with the methods with the AntiForgeryToken
[ValidateAntiForgeryToken]
[Authorize(Roles = "Admin")]
[System.web.Mvc.AuthorizeSectionccess(sectionname = "IT")]
public ActionResult Create()
{
return View();
}
[ValidateAntiForgeryToken]
[Authorize(Roles = "Admin")]
[System.web.Mvc.AuthorizeSectionccess(sectionname = "IT")]
[System.web.Mvc.AuthorizePermitionAccess(PermissonType = "Add")]
[HttpPost]
public ActionResult Create(Welcome_conteudoPage model)
{
DB.Welcome_conteudoPage.Add(model);
DB.SaveChanges();
return Redirect("Index");
return View(model);
}
And this is the View
#using (Html.BeginForm("Create", "ConteudosPageController", FormMethod.Post))
{
#Html.AntiForgeryToken()
<div>
#Html.TextAreaFor(model => model.ConteudoStandard)
</div>
<div>
<input type="submit" value="Inserir" class="btn btn-primary"/>
</div>
<div>
Texto:
#Html.DisplayFor(model => model.ConteudoStandard)
</div>
}
I'm using the AntiForgeryToken on both ends and still get that error. I know that there are thousands of questions like this but I've tried all of the proposed solutions for 3 days and without any result.
EDIT: I forgot to mention that the view is going to call the controller and model for a tinyMCE Editor
It might not be the answer, however, you may have misunderstood what the anti forgery token does and where to use it.
Firstly, when you use #Html.AntiforgeryToken in a view, it registers something in either the session or cookie (can't remember which).
The validate anti forgery token attribute looks for that token and matches it against the passed in token in the hidden field. If it doesn't match, then most likely the post request didn't come from your view.
The thing to note, is that this requires a body parameter on the request to send in the token. You wouldn't have this on requests that don't have a body. A Get request doesn't have a body, and therefore doesn't need the validateantiforgerytoken attribute on it.