C
C#7mo ago
Azazel

❔ Error with showing Images in Azure App Service.

Using Asp.net and Azure Blob Storage and Azure App Service: When I run my API locally on my computer I can receive Images. even if they have slashes, indicating that they are part of a directory:
profileImages/TestUser1/381d4432-2e23-4db5-8b77-b68503c09cea
profileImages/TestUser1/381d4432-2e23-4db5-8b77-b68503c09cea
the same code and the same request fails to run when my API is published to the App service. Instead I get a 404 when trying to request Images with slashes (like the one on top). Images that do not have backslashes in the name instead work normally tho. the endpoint that retrieves the images is the following.
[HttpGet("{fileName}")]
public async Task<IActionResult> Download(string fileName)
{
fileName = System.Net.WebUtility.UrlDecode(fileName);

BusinessLogicMessage<BlobDownloadResult> result = await _filesService.GetBlobAsync(fileName);

if (result.StatusEnum == BusinessLogicStatus.Failure)
{
return BadRequest(result);
}

BlobDownloadResult blobInfo = result.Result!;

return File(blobInfo.Content.ToArray(), blobInfo.Details.ContentType);
}
[HttpGet("{fileName}")]
public async Task<IActionResult> Download(string fileName)
{
fileName = System.Net.WebUtility.UrlDecode(fileName);

BusinessLogicMessage<BlobDownloadResult> result = await _filesService.GetBlobAsync(fileName);

if (result.StatusEnum == BusinessLogicStatus.Failure)
{
return BadRequest(result);
}

BlobDownloadResult blobInfo = result.Result!;

return File(blobInfo.Content.ToArray(), blobInfo.Details.ContentType);
}
I suspect that, because the directory symbol is the same as a web-directory, my API fails to show the image. I do not believe that loading the actual image from blob storage is the problem, as images without slashes load normally. Also if I type in a random name of an image that does not exist I explicitly get a Bad Request stating that the image does not exist, instead of a 404. Any ideas why that behavior may happen?
204 Replies
Mayor McCheese
Mayor McCheese7mo ago
I'd try a minimal reproduction, are you using azure storage locally, or a the local file system, or azurite?
Azazel
Azazel7mo ago
ok im lost already
Mayor McCheese
Mayor McCheese7mo ago
you said, locally it works
Azazel
Azazel7mo ago
I just upload my Images to a Azure storage account
Mayor McCheese
Mayor McCheese7mo ago
what do you mean by locally it works?
Azazel
Azazel7mo ago
When i run it locally I still get the images from the remote Storage account
Mayor McCheese
Mayor McCheese7mo ago
kk azurite is an emulator are you sure UrlDecode is doing what you expect? I'm assuming _fileService is a bare facade over blob storage
Azazel
Azazel7mo ago
I had a problem where the url was encoded, causing / to be converted to %2F i think. So i added that to decode it. Im not sure if its doing the same when not done locally but i would asume it does I can show you the file service if you want. It just handles all the interaction with the storage account so I dont have to do that in the controller.
Mayor McCheese
Mayor McCheese7mo ago
sure why not
Azazel
Azazel7mo ago
ah i cant Ill upload the relevant method
public async Task<BusinessLogicMessage<BlobDownloadResult>> GetBlobAsync(string fileName)
{
BlobClient blobClient = _blobContainerClient.GetBlobClient(fileName);

BusinessLogicMessage<BlobDownloadResult> response;

bool blobExists;

try
{
blobExists = await blobClient.ExistsAsync();
}
catch
{
return new BusinessLogicMessage<BlobDownloadResult>(null, BusinessLogicStatus.Failure,
"File does not exist.");
}

if (blobExists)
{
try
{
BlobDownloadResult blobInfo = await blobClient.DownloadContentAsync();
response = new BusinessLogicMessage<BlobDownloadResult>(blobInfo, BusinessLogicStatus.Success, $"the blob {fileName} was successfully loaded.");
}
catch (Exception ex)
{
response = new BusinessLogicMessage<BlobDownloadResult>(null, BusinessLogicStatus.Failure, "File exists, but download failed.");
}
}
else
{
response = new BusinessLogicMessage<BlobDownloadResult>(null, BusinessLogicStatus.Failure,
"File does not exist.");
}

return response;
}
public async Task<BusinessLogicMessage<BlobDownloadResult>> GetBlobAsync(string fileName)
{
BlobClient blobClient = _blobContainerClient.GetBlobClient(fileName);

BusinessLogicMessage<BlobDownloadResult> response;

bool blobExists;

try
{
blobExists = await blobClient.ExistsAsync();
}
catch
{
return new BusinessLogicMessage<BlobDownloadResult>(null, BusinessLogicStatus.Failure,
"File does not exist.");
}

if (blobExists)
{
try
{
BlobDownloadResult blobInfo = await blobClient.DownloadContentAsync();
response = new BusinessLogicMessage<BlobDownloadResult>(blobInfo, BusinessLogicStatus.Success, $"the blob {fileName} was successfully loaded.");
}
catch (Exception ex)
{
response = new BusinessLogicMessage<BlobDownloadResult>(null, BusinessLogicStatus.Failure, "File exists, but download failed.");
}
}
else
{
response = new BusinessLogicMessage<BlobDownloadResult>(null, BusinessLogicStatus.Failure,
"File does not exist.");
}

return response;
}
it just opens the blob and returns a result object And the thing is, that if I type in the name of a blob that does not exist I get a Bad request instead of a 404
Mayor McCheese
Mayor McCheese7mo ago
Yeah I'm struggling with that part I'm looking at the docs
Azazel
Azazel7mo ago
ok
Mayor McCheese
Mayor McCheese7mo ago
You've got some likely false assumptions in your exceptions btw
Azazel
Azazel7mo ago
what do you mean
Mayor McCheese
Mayor McCheese7mo ago
catch (Exception ex)
{
response = new BusinessLogicMessage<BlobDownloadResult>(null, BusinessLogicStatus.Failure, "File exists, but download failed.");
}
catch (Exception ex)
{
response = new BusinessLogicMessage<BlobDownloadResult>(null, BusinessLogicStatus.Failure, "File exists, but download failed.");
}
catching the super-exception is frequently a bad idea at this level
Azazel
Azazel7mo ago
okay what would be recomended?
Mayor McCheese
Mayor McCheese7mo ago
if a blob fails to download a RequestFailedException will be thrown maybe you should catch that
Azazel
Azazel7mo ago
and try again?
Mayor McCheese
Mayor McCheese7mo ago
it depends it's kind of a complex area
Azazel
Azazel7mo ago
Ah you want me to catch that exception in particular?
Mayor McCheese
Mayor McCheese7mo ago
try
{

}
catch(RequestFailedException ex) when(ex.Status == 429) // worth a wait and retry for instance
{
wait and retry logic here
}
try
{

}
catch(RequestFailedException ex) when(ex.Status == 429) // worth a wait and retry for instance
{
wait and retry logic here
}
for example ideally you only catch what you can handle so anything that goes wrong you catch and then blind back up.
Azazel
Azazel7mo ago
ok I did
catch (Exception ex) when (ex is RequestFailedException)
catch (Exception ex) when (ex is RequestFailedException)
ill implement retry logic later once i read up on the topic some more, I do not want to be stuck in a retry loop
Mayor McCheese
Mayor McCheese7mo ago
nah I get that you don't want to retry forever
Azazel
Azazel7mo ago
for now I just want to be able to see the same behavior on my App service as in development (when running the backend in memory on my pc over localhost)
Mayor McCheese
Mayor McCheese7mo ago
change to... catch (Exception ex) when (ex is rfe RequestFailedException) then you'll have rfe as a reference to RequestFailedException in your catchblock
Azazel
Azazel7mo ago
ok
Mayor McCheese
Mayor McCheese7mo ago
so, if it's a status code of 404, it's not found
Azazel
Azazel7mo ago
yeah
Mayor McCheese
Mayor McCheese7mo ago
for example
Azazel
Azazel7mo ago
but if an image is not found my code will return a bad requestr so the 404 does not originate from my code right? exceptions will cause 500 if im not mistaken
Mayor McCheese
Mayor McCheese7mo ago
let me look at code again
Azazel
Azazel7mo ago
ok Im thinking its something with routing not set up correctly in azure
Mayor McCheese
Mayor McCheese7mo ago
I was about to say that
Azazel
Azazel7mo ago
ok I have no clue when it comes to azure i rarely use it.
Mayor McCheese
Mayor McCheese7mo ago
I don't know how friendly [HttpGet("{fileName}")] public async Task<IActionResult> Download(string fileName) { is
Azazel
Azazel7mo ago
ah yeah wildcard is better I think no? I tried both
Mayor McCheese
Mayor McCheese7mo ago
I'm not an expert at routing honestly, using file path separators is probably an issue is there a requirement that you do so?
Azazel
Azazel7mo ago
I could use a different seperator then change it to / to get the file but that sounds scuffed
Mayor McCheese
Mayor McCheese7mo ago
I'd personally have to reserach routing behavior to see how something like.... /[controller]/test/test/test/test.png ends up being routed
Azazel
Azazel7mo ago
becuase the files have / as seperators
Mayor McCheese
Mayor McCheese7mo ago
NB: blob storage doesn't actually create folders with /'s
Azazel
Azazel7mo ago
it creates directories
Mayor McCheese
Mayor McCheese7mo ago
most storage ux treats the / as organization unit
Azazel
Azazel7mo ago
yeah thats right
Mayor McCheese
Mayor McCheese7mo ago
but blog storage itself doesn't know about directories
Azazel
Azazel7mo ago
yeah yeah
Mayor McCheese
Mayor McCheese7mo ago
but question how are the files getting there?
Azazel
Azazel7mo ago
I upload them with another endpoint
Mayor McCheese
Mayor McCheese7mo ago
you do, or users do?
Azazel
Azazel7mo ago
users do but I choose the path
Mayor McCheese
Mayor McCheese7mo ago
are you validating the files at all?
Azazel
Azazel7mo ago
I am
Mayor McCheese
Mayor McCheese7mo ago
kk
Azazel
Azazel7mo ago
I wrote a validator for that
Mayor McCheese
Mayor McCheese7mo ago
otherwise you're building a malware delivery platform 🙂 discord is dealing with that currently
Azazel
Azazel7mo ago
lol yeah ik it just takes pngs and looks that they are 124 x 124
Mayor McCheese
Mayor McCheese7mo ago
ah so you actually insepct it's a png, that's mostly good png is usually a safe format iirc, you can't easily embed in RCE type code I think you're issue is somehwere here...
fileName = System.Net.WebUtility.UrlDecode(fileName);
BusinessLogicMessage<BlobDownloadResult> result = await _filesService.GetBlobAsync(fileName);
fileName = System.Net.WebUtility.UrlDecode(fileName);
BusinessLogicMessage<BlobDownloadResult> result = await _filesService.GetBlobAsync(fileName);
where either routing isn't doing as you expect or UrlDecode isn't doing as you expect
Azazel
Azazel7mo ago
hm. but wouldnt that just result in a Bad Request instead like its tries to look up a nonsense file and just finds nothing
Mayor McCheese
Mayor McCheese7mo ago
you might want to createa dummy route in azure that looks like this...
[HttpGet("check/{filename}")]
public async Task<IActionResult> Download(string fileName)
{
fileName = System.Net.WebUtility.UrlDecode(fileName);
return Ok(fileName);
}
[HttpGet("check/{filename}")]
public async Task<IActionResult> Download(string fileName)
{
fileName = System.Net.WebUtility.UrlDecode(fileName);
return Ok(fileName);
}
I don't know who wins in that scenario, iirc for routing, specificity wins, so if your path is /[controller]/check/blah/blah/blah.png you should get back blah/blah/blah.png That's kind of a hinky way to do it with redeploying and all, but it's probably your shortest path to check
Azazel
Azazel7mo ago
ok ill try wait
Mayor McCheese
Mayor McCheese7mo ago
I just verified that System.Net.WebUtility.UrlDecode("%2fblah%2fblah%2fblah.png"); is /blah/blah/blah.png Glancing at your code you don't seem to have the ability to really determine if the blob is there or not from the controller perspective
Azazel
Azazel7mo ago
I do not want to give to much inside outside of success or no success
Mayor McCheese
Mayor McCheese7mo ago
well I guess you are sending back a message too
Azazel
Azazel7mo ago
hm okay what would you change then?
Mayor McCheese
Mayor McCheese7mo ago
oh my controller code was wrong
Azazel
Azazel7mo ago
yea
Mayor McCheese
Mayor McCheese7mo ago
casing
Azazel
Azazel7mo ago
ah i was losing my mind over here lol
Mayor McCheese
Mayor McCheese7mo ago
[HttpGet("check/{filename}")] public async Task<IActionResult> Download(string filename) { fileName = System.Net.WebUtility.UrlDecode(filename); return Ok(fileName); } not fileName
Azazel
Azazel7mo ago
i see isee
Mayor McCheese
Mayor McCheese7mo ago
some of it is how you percieve success, 404 is an okay status to return, you asked for this file, it's not there.
Azazel
Azazel7mo ago
yeah but the way I handle errors currently dont support multiple stati its either it worked or it didnt I googled to find a better way of handling errors but it doesnt seem worth it
Mayor McCheese
Mayor McCheese7mo ago
yeah it was worth checking, I expected it would
Azazel
Azazel7mo ago
yep yep : )
Mayor McCheese
Mayor McCheese7mo ago
so there's something going on I'm not seeing in the code, or something else is happening in azure
Azazel
Azazel7mo ago
it all falls back on the BusinessLogicMessage this is what I use when i run some kind of business logic.
namespace TourGuideApi.Models
{
public class BusinessLogicMessage<T> : BusinessLogicMessage
{
public T? Result { get; set; }

public BusinessLogicMessage(T result)
{
Result = result;
StatusEnum = BusinessLogicStatus.Success;
Message = string.Empty;
}

public BusinessLogicMessage(T? result, BusinessLogicStatus statusEnum, string message)
{
Result = result;
StatusEnum = statusEnum;
Message = message;
}

public override string ToString()
{
if (this.Result == null)
{
BusinessLogicMessage businessLogicMessage = new BusinessLogicMessage(this.StatusEnum, this.Message);
return businessLogicMessage.ToString();
}
else
{
return base.ToString();
}
}
}

public class BusinessLogicMessage
{
public BusinessLogicMessage()
{
StatusEnum = BusinessLogicStatus.Success;
Message = string.Empty;
}

public BusinessLogicMessage(BusinessLogicStatus statusEnum, string message)
{
StatusEnum = statusEnum;
Message = message;
}

public string Status => StatusEnum.ToString();
internal BusinessLogicStatus StatusEnum { get; set; }
public string Message { get; set; }
}

public enum BusinessLogicStatus
{
Success,
Failure,
Warning
}
}
namespace TourGuideApi.Models
{
public class BusinessLogicMessage<T> : BusinessLogicMessage
{
public T? Result { get; set; }

public BusinessLogicMessage(T result)
{
Result = result;
StatusEnum = BusinessLogicStatus.Success;
Message = string.Empty;
}

public BusinessLogicMessage(T? result, BusinessLogicStatus statusEnum, string message)
{
Result = result;
StatusEnum = statusEnum;
Message = message;
}

public override string ToString()
{
if (this.Result == null)
{
BusinessLogicMessage businessLogicMessage = new BusinessLogicMessage(this.StatusEnum, this.Message);
return businessLogicMessage.ToString();
}
else
{
return base.ToString();
}
}
}

public class BusinessLogicMessage
{
public BusinessLogicMessage()
{
StatusEnum = BusinessLogicStatus.Success;
Message = string.Empty;
}

public BusinessLogicMessage(BusinessLogicStatus statusEnum, string message)
{
StatusEnum = statusEnum;
Message = message;
}

public string Status => StatusEnum.ToString();
internal BusinessLogicStatus StatusEnum { get; set; }
public string Message { get; set; }
}

public enum BusinessLogicStatus
{
Success,
Failure,
Warning
}
}
litterally every service i have uses this as the return type
Mayor McCheese
Mayor McCheese7mo ago
On the surface, your controller looks like it should do what it should
Azazel
Azazel7mo ago
like i could change the enum to the HTTP codes but then again handling all the cases from the controller sounds bothersome
Mayor McCheese
Mayor McCheese7mo ago
do you have azcopy ?
Azazel
Azazel7mo ago
no
Mayor McCheese
Mayor McCheese7mo ago
Copy or move data to Azure Storage by using AzCopy v10
AzCopy is a command-line utility that you can use to copy data to, from, or between storage accounts. This article helps you download AzCopy, connect to your storage account, and then transfer data.
Azazel
Azazel7mo ago
its so you can mirror my setup?
Mayor McCheese
Mayor McCheese7mo ago
nah you can try and use azcopy to get the same blob unless that's what you mean by mirror settup
Azazel
Azazel7mo ago
no no
Mayor McCheese
Mayor McCheese7mo ago
so you should be able to use azcopy to pull the same blob you can use storage explorer too but storage explorer is possibly too friendly for a check
Azazel
Azazel7mo ago
I used IAM or what ever that is called to authorize both client and app service i hope thats not an issue
Mayor McCheese
Mayor McCheese7mo ago
it's like literally azcopy storageaccounturl localfile I mean if you have rbac set up correctly it should be okay
Azazel
Azazel7mo ago
ok wait do they always have urls?
Mayor McCheese
Mayor McCheese7mo ago
which? blob storage? every blob has a url
Azazel
Azazel7mo ago
ah the containers do okok
Mayor McCheese
Mayor McCheese7mo ago
yeah I mean you can eyeball it too, but everything looks kosher right now
Azazel
Azazel7mo ago
yeah
Mayor McCheese
Mayor McCheese7mo ago
I might have coded some thing different
Azazel
Azazel7mo ago
I mean I can pull the files locally using the backend so I dont think its anything with the storage account
Mayor McCheese
Mayor McCheese7mo ago
what ASP are you using?
Azazel
Azazel7mo ago
7.0 i think
Mayor McCheese
Mayor McCheese7mo ago
err
Azazel
Azazel7mo ago
ehh not goodß ?
Mayor McCheese
Mayor McCheese7mo ago
app services run in an app service plan
Azazel
Azazel7mo ago
yep
Mayor McCheese
Mayor McCheese7mo ago
so your app service plan, what is the OS for instance?
Azazel
Azazel7mo ago
linux wait is that the problem?
Mayor McCheese
Mayor McCheese7mo ago
are you using linux locally?
Azazel
Azazel7mo ago
no windows locally
Mayor McCheese
Mayor McCheese7mo ago
potentially
Azazel
Azazel7mo ago
yeah they use backslash
Mayor McCheese
Mayor McCheese7mo ago
linux cares about some things windows doesn't file case, etc. I mean what you're calling filename is just a string
Azazel
Azazel7mo ago
hm but would linux or windows inpact routing
Mayor McCheese
Mayor McCheese7mo ago
nah at least, I'm asying nah 🙂
Azazel
Azazel7mo ago
ok
Mayor McCheese
Mayor McCheese7mo ago
obviously your routing is working we proved that
Azazel
Azazel7mo ago
but what we both agree on is that the 404 is thown buy the Azure app service somehow
Mayor McCheese
Mayor McCheese7mo ago
and while I don't like your error handling, your blob code looks reasonable
Azazel
Azazel7mo ago
yeah i dont like it either lo ll
Mayor McCheese
Mayor McCheese7mo ago
the thing that would care about case would really be the azure storage resource itself it's an http call at the end of the day does it consistently fail?
Azazel
Azazel7mo ago
yes anything with a slash doesnt work but without it works if I run it locally it always works and we verified that the input is correct like what our controller is passing into my service
Mayor McCheese
Mayor McCheese7mo ago
I don't know of any subtleties between linux and windows with asp.net core and the code you've shown
Azazel
Azazel7mo ago
hm I could change the controller to just pass in a string over a model
Mayor McCheese
Mayor McCheese7mo ago
I'm gonna try and repro real quick
Azazel
Azazel7mo ago
yeah while you do that i do what i suggested okay lol
[HttpGet("get-blob")]
public async Task<IActionResult> GetBlob(string fileName)
{
BusinessLogicMessage<BlobDownloadResult> result = await _filesService.GetBlobAsync(fileName);

if (result.StatusEnum == BusinessLogicStatus.Failure)
{
return BadRequest(result);
}

BlobDownloadResult blobInfo = result.Result!;

return File(blobInfo.Content.ToArray(), blobInfo.Details.ContentType);
}
[HttpGet("get-blob")]
public async Task<IActionResult> GetBlob(string fileName)
{
BusinessLogicMessage<BlobDownloadResult> result = await _filesService.GetBlobAsync(fileName);

if (result.StatusEnum == BusinessLogicStatus.Failure)
{
return BadRequest(result);
}

BlobDownloadResult blobInfo = result.Result!;

return File(blobInfo.Content.ToArray(), blobInfo.Details.ContentType);
}
this works its litterally just the weird route but that makes no sense to me
Mayor McCheese
Mayor McCheese7mo ago
okay I have a working thing locally
Azazel
Azazel7mo ago
ok btw did you see? it works on azure aswell. the only difference is the route
Mayor McCheese
Mayor McCheese7mo ago
haven't tried azure yet creating an empty weba pp
Azazel
Azazel7mo ago
ok
Mayor McCheese
Mayor McCheese7mo ago
web deploying now this is a frigid startup nm cold start
Azazel
Azazel7mo ago
ok
Mayor McCheese
Mayor McCheese7mo ago
must be the f tier really sucks
Azazel
Azazel7mo ago
yeah I think we can test the route seperately im going to try that if so we dont need to bother with blobs at all
Mayor McCheese
Mayor McCheese7mo ago
hhhhhhmmmmmmm I'm getting a 404 lemme check kudu
Azazel
Azazel7mo ago
ok
Mayor McCheese
Mayor McCheese7mo ago
okay lemme add a non slash blob
Azazel
Azazel7mo ago
yep Okay It doesnt work in general
[HttpGet("{fileName}")]
public async Task<IActionResult> Download(string fileName)
{
fileName = System.Net.WebUtility.UrlDecode(fileName);

//BusinessLogicMessage<BlobDownloadResult> result = await _filesService.GetBlobAsync(fileName);

//if (result.StatusEnum == BusinessLogicStatus.Failure)
//{
// return BadRequest(result);
//}

//BlobDownloadResult blobInfo = result.Result!;

//return File(blobInfo.Content.ToArray(), blobInfo.Details.ContentType);

return Ok(fileName);
}
[HttpGet("{fileName}")]
public async Task<IActionResult> Download(string fileName)
{
fileName = System.Net.WebUtility.UrlDecode(fileName);

//BusinessLogicMessage<BlobDownloadResult> result = await _filesService.GetBlobAsync(fileName);

//if (result.StatusEnum == BusinessLogicStatus.Failure)
//{
// return BadRequest(result);
//}

//BlobDownloadResult blobInfo = result.Result!;

//return File(blobInfo.Content.ToArray(), blobInfo.Details.ContentType);

return Ok(fileName);
}
this doesnt work on azure aswell
Mayor McCheese
Mayor McCheese7mo ago
switch to a windows asp
Azazel
Azazel7mo ago
ok ill try
Azazel
Azazel7mo ago
wait wha Does it work? on windows? NAH
Mayor McCheese
Mayor McCheese7mo ago
well wait that image has no slashes
Azazel
Azazel7mo ago
ah
Azazel
Azazel7mo ago
404 yeah
Mayor McCheese
Mayor McCheese7mo ago
but works locally
Azazel
Azazel7mo ago
yeah i swap to windows real quick I hope I wont have any problems unrelated to this
Mayor McCheese
Mayor McCheese7mo ago
filename = System.Net.WebUtility.UrlDecode(filename);

BlobClient client = new BlobClient("my-bare-connection-string", "container", filename);

var result = await client.DownloadContentAsync();

return File(result.Value.Content.ToArray(), "image/x-png");
filename = System.Net.WebUtility.UrlDecode(filename);

BlobClient client = new BlobClient("my-bare-connection-string", "container", filename);

var result = await client.DownloadContentAsync();

return File(result.Value.Content.ToArray(), "image/x-png");
swapping back is easy
Azazel
Azazel7mo ago
ye
Mayor McCheese
Mayor McCheese7mo ago
NB: windows asp's are more expensive I'm making a change and redeploying
Azazel
Azazel7mo ago
to windows?
Mayor McCheese
Mayor McCheese7mo ago
nah
Azazel
Azazel7mo ago
ok how do I swap i only have the option to create a new app
Mayor McCheese
Mayor McCheese7mo ago
you probably have to use az cli
Azazel
Azazel7mo ago
i got this
No description
Azazel
Azazel7mo ago
x86?
Mayor McCheese
Mayor McCheese7mo ago
win-x64
Azazel
Azazel7mo ago
ok ai windows does not support 7.0
Azazel
Azazel7mo ago
like what i showed? can you show me the code?
Mayor McCheese
Mayor McCheese7mo ago
using Azure.Storage.Blobs;
using Microsoft.AspNetCore.Mvc;

namespace Scratch.Web.Controllers;

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};

private readonly ILogger<WeatherForecastController> _logger;

public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}

[HttpGet]
public async Task<IActionResult> Get([FromQuery]string filename)
{
filename = System.Net.WebUtility.UrlDecode(filename);

BlobClient client = new BlobClient("my-connection-string", "container", filename);

var result = await client.DownloadContentAsync();

return File(result.Value.Content.ToArray(), "image/x-png");
}
}
using Azure.Storage.Blobs;
using Microsoft.AspNetCore.Mvc;

namespace Scratch.Web.Controllers;

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};

private readonly ILogger<WeatherForecastController> _logger;

public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}

[HttpGet]
public async Task<IActionResult> Get([FromQuery]string filename)
{
filename = System.Net.WebUtility.UrlDecode(filename);

BlobClient client = new BlobClient("my-connection-string", "container", filename);

var result = await client.DownloadContentAsync();

return File(result.Value.Content.ToArray(), "image/x-png");
}
}
Azazel
Azazel7mo ago
ok looks like a fine alternative no? i just use query strings
Mayor McCheese
Mayor McCheese7mo ago
yah or you could probably build a custom route handler
Azazel
Azazel7mo ago
eh i got other things to do x) I need to build a chat system too
Mayor McCheese
Mayor McCheese7mo ago
all you'd do is drop the "{filename}" from HttpGet() and change filename [FromQuery]string filename
Azazel
Azazel7mo ago
yep Thanks for helping atleast I got some reassurance that it truly is a weird problem
Mayor McCheese
Mayor McCheese7mo ago
yeah it's a bit weird and I'm sure some folks better versed in webapi could say "oh, just add this" I'm going to deploy to windows asp
Azazel
Azazel7mo ago
ok but dont bother too much. Im just going to use the query stuff : ) ) unless you are yourself are interested
Azazel
Azazel7mo ago
damn
Mayor McCheese
Mayor McCheese7mo ago
and works local could be a gateway issue
Azazel
Azazel7mo ago
yeah
Mayor McCheese
Mayor McCheese7mo ago
this is a known issue
Azazel
Azazel7mo ago
like with azure app service in general?
Mayor McCheese
Mayor McCheese7mo ago
yeah there is a pendning fix
Azazel
Azazel7mo ago
ffs I spend valuable sleep on this
Mayor McCheese
Mayor McCheese7mo ago
there are work arounds but they all sorta suck
Azazel
Azazel7mo ago
query parameter it is
Mayor McCheese
Mayor McCheese7mo ago
@Azazel https://github.com/Azure/azure-functions-host/issues/9290 if you want to see more about it and the pending fix... https://github.com/Azure/azure-functions-host/pull/9402 maybe it is merged This is an opt-in feature customers needs to explicitly opt-in by setting the WEBSITE_RESTORE_RAW_REQUEST_PATH app setting.
Azazel
Azazel7mo ago
yeah no I will not do that Ill just wait till its merged
Mayor McCheese
Mayor McCheese7mo ago
yeah that settings isn't working for me
Azazel
Azazel7mo ago
small indie company @🎄Mayor McCheese 🎄 Oi sorry to bother you. I remembered that you told me my error handling was not so good. Any pointers you could show me to improve or maybe some designpatterns that would allow all Internal logic to be handled in services. I want to be able to create a IActionResult from my BusinessLogicMessage.
Mayor McCheese
Mayor McCheese7mo ago
asp.net core has a "global exception handler" that's where you want to catch "exception" so, ideally you only catch what you can handle
Azazel
Azazel7mo ago
so my services should only return what I need and error handling will happen globalyß ?
Mayor McCheese
Mayor McCheese7mo ago
for example, cosmos database throws an exception when documents aren't found so
Azazel
Azazel7mo ago
Ahh that way I only handle each exeption once
Mayor McCheese
Mayor McCheese7mo ago
try
{
return await container.ReadItemAsync<MyModel>(myKey, new PartitionKey(myPartitionKey));
}
catch(CosmosException ex) when (ex.Status == StatusCode.NotFound)
{
return new MyModel { Id = myKey, Partition = myPartitionKey };
}
try
{
return await container.ReadItemAsync<MyModel>(myKey, new PartitionKey(myPartitionKey));
}
catch(CosmosException ex) when (ex.Status == StatusCode.NotFound)
{
return new MyModel { Id = myKey, Partition = myPartitionKey };
}
so in the above we can "handle" a 404 by returning a new empty document so, a frequent anti pattern you'll see is...
public void DoSoemthing()
{
try
{
// something bad happens in this code.
}
catch(Exception ex)
{
_logger.LogError(ex, "Something bad happened");
throw;
}
}

public void DoMeFirst()
{
try
{
// do some code first
DoSomething();
}
catch(Exception ex)
{
_logger.LogError(ex, "Something bad happened");
throw;
}
}
public void DoSoemthing()
{
try
{
// something bad happens in this code.
}
catch(Exception ex)
{
_logger.LogError(ex, "Something bad happened");
throw;
}
}

public void DoMeFirst()
{
try
{
// do some code first
DoSomething();
}
catch(Exception ex)
{
_logger.LogError(ex, "Something bad happened");
throw;
}
}
so in the code above, you'll get two log entries for the same error so probably don't do that now consider you have a console app that does some work...
static async Task Main()
{
var errorCount = 0;

while(true)
{
try
{
DoWOrk();
errorCount = 0;
}
catch(exception ex)
{
if(++errorCcount > 10) throw;

_logger.LogError(ex, "Something bad happening);
await Task.Delay(TimeSpan.FromSeconds(5);
}
}
}
static async Task Main()
{
var errorCount = 0;

while(true)
{
try
{
DoWOrk();
errorCount = 0;
}
catch(exception ex)
{
if(++errorCcount > 10) throw;

_logger.LogError(ex, "Something bad happening);
await Task.Delay(TimeSpan.FromSeconds(5);
}
}
}
so in our main worker loop, we'll catch any exception assuming it's a transient falure, wait and then continue again we don't want to keep retrying forever though so if our error count surges then we'll shut down the app they are all pretty naive examples
Azazel
Azazel7mo ago
yep they all have some flaws
Mayor McCheese
Mayor McCheese7mo ago
but the idea is that you want to catch specific exceptions that you can address the issues with otherwise just let the error bubble up
Azazel
Azazel7mo ago
if I let the exeptions be handled globaly, I dont have to care for edgecases and can handle the edgecases on a per exception basis right?
Mayor McCheese
Mayor McCheese7mo ago
basically though I don't like the word edgecase it's possible with cosmosdb for instance, that you'll ask for document that doesn't exist. returning a new document isn't an unreasonable reaction
Azazel
Azazel7mo ago
ok I get it
Mayor McCheese
Mayor McCheese7mo ago
in your image case
Azazel
Azazel7mo ago
I rip that fucking BusinessLogicMessage out
Mayor McCheese
Mayor McCheese7mo ago
what is the image doesn't exit?
Azazel
Azazel7mo ago
if it doesnt exist ill return either null return an empty image
Mayor McCheese
Mayor McCheese7mo ago
what about?
No description
Azazel
Azazel7mo ago
ye but if it cant find the container i let the exeption fire and handle it globaly
Mayor McCheese
Mayor McCheese7mo ago
if that suits your code, then yeah
Azazel
Azazel7mo ago
ok : ) thanks a lot im really thankfull of all the help
Mayor McCheese
Mayor McCheese7mo ago
so for an HttpClient for example if you get a 500 what should you do? a retry is probably reasonable
Azazel
Azazel7mo ago
yeah
Mayor McCheese
Mayor McCheese7mo ago
but you don't want to keep retrying
Mayor McCheese
Mayor McCheese7mo ago
there's some libraries like https://github.com/App-vNext/Polly
GitHub
GitHub - App-vNext/Polly: Polly is a .NET resilience and transient-...
Polly is a .NET resilience and transient-fault-handling library that allows developers to express policies such as Retry, Circuit Breaker, Timeout, Bulkhead Isolation, and Fallback in a fluent and ...
Mayor McCheese
Mayor McCheese7mo ago
which help with things like retries and fallbacks
Azazel
Azazel7mo ago
basically what you did in the 3. example just better and as a library the non naive appoach
Accord
Accord7mo ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.
Want results from more Discord servers?
Add your server
More Posts
Issues with EFCoreHello everyone, I am trying to use ApplyConfigurationsFromAssembly but it seems to not be finding an❔ Could u help me plzI´m learning coding with a youtube course, and i´m trying to do a crud, but this error with the form❔ Modular programming ?Hello, I am currently studying video game programming in C#. As part of this, we have a project to ❔ Is this possible in WEBAPI to add logic between JWT token validation and the authorization?I read a blog about the AspNetCore WebApi: https://jasonwatmore.com/post/2022/02/18/net-6-role-based✅ docker build with dotnet 8ERROR: Service 'vmg-dashboards-api' failed to build: The command '/bin/sh -c dotnet restore "vmg.dasMake every textblock in an itemscontrol with an OCollection<string> as the source have a click eventI have an itemscontrl with a OCollection as the source which means it can be updated i have a textbl❔ Validation of appsettings configuration before running the applicationHello. I would like to validate entries in the appsettings configuration at application startup to ❔ Migrate AppDomain (.net framework) to AssemblyLoadContext (.net core)I need help converting this code to the .net core equivalent by using AppDomain here, ensured that t❔ Form goes fully transparent please helpi was trying to make blurry panel then i searched and i found something but the problem is i see squ❔ ✅ Mind explaining a code to me?```cs public static int? Closest(int[] arr) { var min = arr.Distinct().Where(x => Math.Abs(x)