Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
power crystals
Jun 6, 2007

Who wants a belly rub??

For games like that a lot of the time the load times may be dominated by how mods interact with each other, where each one isn't the culprit specificaally but they're all trying to do "for each Thing" while also adding more Things.

The other optionis if you can find the "load a mod" part of the code is to use dnspy or something like it and manually time how long it takes for each one. For 70 it's not infeasible to do that by hand. If you get real excited you could even edit the assembly on disk to make the game emit the times itself into a file.

Adbot
ADBOT LOVES YOU

zokie
Feb 13, 2006

Out of many, Sweden
Ran into a weird situation with aspnetcore deployed on premise IIS. It just wouldn’t update one environment variable. We tried deleting the website & app pool but still the environment variable (process scope) remained. We didn’t wanna restart the server, but what the hell?? Anyone knows what is up?

The website was created using create/deploy iis thing on machine group task in in azure Devops pipeline.

Munkeymon
Aug 14, 2003

Motherfucker's got an
armor-piercing crowbar! Rigoddamndicu𝜆ous.



Is there a best practice for setting session data after you've logged a user in in ASP MVC 5 (yep, still on Framework)? Logging in invalidates the current session so anything added to it just gets dropped on the floor when the request is done, but I don't see a way to add to the new session before the next request, so I'm planning on stuffing some stuff in a short-lived cookie and adding it to the session on the next request which feels kinda gross and like there ought to be a better way.

raminasi
Jan 25, 2005

a last drink with no ice

Hughmoris posted:

I've never used perfview before but I'll give that a look, thanks!

Beware, it's definitely a power user tool. It's super useful once you learn how to use it but there can be a really steep learning curve.

Kyte
Nov 19, 2013

Never quacked for this

Munkeymon posted:

Is there a best practice for setting session data after you've logged a user in in ASP MVC 5 (yep, still on Framework)? Logging in invalidates the current session so anything added to it just gets dropped on the floor when the request is done, but I don't see a way to add to the new session before the next request, so I'm planning on stuffing some stuff in a short-lived cookie and adding it to the session on the next request which feels kinda gross and like there ought to be a better way.

fwiw I recall that TempData by default works through a short-lived cookie so it's not like you're alone there

Dog on Fire
Oct 2, 2004

I'm trying to create a background loop that periodically makes an HTTP request, but I'm not sure how to create the loop and continue with the execution while the loop is going.

code:
{
    await CreateTheHttpRequestLoopAndNeverReturnAsync();
    DoMoreStuff();
}
If I do this, it never gets to DoMoreStuff(), does it? If I remove the await, the compiler complains, but it seems to be kind of what I want to achieve (the loop-creation function just returning and leaving the loop going on).

It's probably a real basic thing about async/await, but it's something that I've never gotten.

Red Mike
Jul 11, 2011
code:
{
    _ = RunThingAsync(); //this starts and then runs in the background
    DoMoreStuff();
}
Generally you'll want to be safe and instead do:

code:
{
    _myBackgroundTask = RunThingAsync(); //this starts and then runs in the background
    DoMoreStuff();

    //at some point in the process/regularly/etc
    if(_myBackgroundTask.IsFaulted) 
    { ... }
}

SirViver
Oct 22, 2008
If you want to do "endless" background work it should IMO be done on a separate thread, optionally with a CancellationToken so your main application is able to "nicely" get the background thread to stop when the app wants to exit. Async/await doesn't really come into play for this.

Jen heir rick
Aug 4, 2004
when a woman says something's not funny, you better not laugh your ass off
You can also use the Timer class to raise an event every n seconds.

biznatchio
Mar 31, 2001


Buglord

SirViver posted:

If you want to do "endless" background work it should IMO be done on a separate thread, optionally with a CancellationToken so your main application is able to "nicely" get the background thread to stop when the app wants to exit. Async/await doesn't really come into play for this.

Using async is perfectly acceptable for endless background work loops, as long as the work loop itself uses async/await internally rather than doing blocking work. But yes, pass a CancellationToken to the method so it can be stopped.

I use a pattern similar to this a lot to encapsulate such async background work within a class that can just simply be disposed to stop the background work:

code:
public class SomeClass : IDisposable, IAsyncDisposable
{
    private readonly CancellationTokenSource _disposedCts = new CancellationTokenSource();
    private readonly Task _processingTask;

    public SomeClass()
    {
        _processingTask = ProcessingLoopAsync(_disposedCts.Token);
    }

    public void Dispose()
    {
        DisposeAsync().AsTask().Wait();
    }

    public async ValueTask DisposeAsync()
    {
        _disposedCts.Cancel();
        try { await _processingTask; } catch { }
    }

    private async Task ProcessingLoopAsync(CancellationToken cancellationToken)
    {
        while (!cancellationToken.IsCancellationRequested)
        {
            // do stuff here
            // with "await Task.Delay(timespan, cancellationToken)" for loops that do stuff on intervals
        }
    }
}

biznatchio fucked around with this message at 16:02 on Jun 1, 2023

zokie
Feb 13, 2006

Out of many, Sweden
Use the BackgroundService or IHostedService I think it’s in Microsoft.Extensions.Hosting

Kyte
Nov 19, 2013

Never quacked for this

Red Mike posted:

code:
{
    _ = RunThingAsync(); //this starts and then runs in the background
    DoMoreStuff();
}
Generally you'll want to be safe and instead do:

code:
{
    _myBackgroundTask = RunThingAsync(); //this starts and then runs in the background
    DoMoreStuff();

    //at some point in the process/regularly/etc
    if(_myBackgroundTask.IsFaulted) 
    { ... }
}

Why not await the background task?

Jabor
Jul 16, 2010

#1 Loser at SpaceChem

Kyte posted:

Why not await the background task?

Because then you can't do anything else on the awaiting thread until the background task finishes?

Oww My Eye
Jun 22, 2006
Got me a movie

Red Mike posted:

code:
{
    _ = RunThingAsync(); //this starts and then runs in the background
    DoMoreStuff();
}
Generally you'll want to be safe and instead do:

code:
{
    _myBackgroundTask = RunThingAsync(); //this starts and then runs in the background
    DoMoreStuff();

    //at some point in the process/regularly/etc
    if(_myBackgroundTask.IsFaulted) 
    { ... }
}

One thing to add is that the implementation of RunThingAsync matters. If it’s code wrapped in a Task.Run, you are probably fine. If it’s some regular async Task code, DoMoreStuff won’t start until the first await inside RunThingAsync is hit.

code:
Task RunThingAsync()
{
    Thread.Sleep(10000);
    await SomeAsyncMethod(); // At 10s in, this is when DoMoreStuff would start
    // Other work
}

Red Mike
Jul 11, 2011
Yeah, that's true, and also if any code before the first await throws an exception, that'll get thrown at your initial call site (instead of getting caught in the exception so you can check for it with Task.IsFaulted).

code:
Task RunThingAsync()
{
    throw new Exception("thing1");
    await SomeAsyncMethod();
    throw new Exception("thing2");
}
"thing1" exception would get thrown as soon as you call RunThingAsync().
If instead nothing got thrown until "thing2", that other exception would not get thrown but instead cause the Task to become faulted (and as soon as/if you awaited the Task then, you'd get the exception).

Lots of quirks and edge cases with all of this, you generally want to keep it simple and avoid the entire thing if you can (by using built-in things like IHostedService, or whatever framework you're using might have, etc).

Oww My Eye
Jun 22, 2006
Got me a movie
I really like async/await and Tasks but they can be really quirky. I’ve seen some pretty gnarly code bugs due to some of those. Relatedly, does anyone know any good analyzers for catching some of these issues?

Kyte
Nov 19, 2013

Never quacked for this

Jabor posted:

Because then you can't do anything else on the awaiting thread until the background task finishes?

No I mean like:
code:
var bgTask = BackgroundTask.Execute();

(other work)

try {
   await bgTask;
} catch (...) {
   (...)
}
While yeah IsFaulted is non-blocking you can't let go of the task or you risk an unobserved task exception. You could put the task into a queue so you can check it later but that has its own issues.

rarbatrol
Apr 17, 2011

Hurt//maim//kill.
What do you mean by unobserved task exceptions? I thought that back when async/await was introduced, tasks would no longer cause unhandled exceptions unless of course you're doing something nasty like async void.

Kyte
Nov 19, 2013

Never quacked for this

rarbatrol posted:

What do you mean by unobserved task exceptions? I thought that back when async/await was introduced, tasks would no longer cause unhandled exceptions unless of course you're doing something nasty like async void.

Maybe my knowledge is wrong but I'm pretty sure a faulted task eventually needs to be unwrapped and observed (whether via await or older mechanisms) or it'll eventually bubble up to the runtime? I know async void is dangerous because the task cannot be captured and therefore observed, but if you deliberately let a task go aren't got causing essentially the same behavior?

biznatchio
Mar 31, 2001


Buglord
Unobserved faulted tasks will cause the process to terminate in .Net Framework 4 -- at an indeterminate time because it can only happen when the Task is finalized, and that's at the mercy of the GC. Starting with .Net Framework 4.5, and all versions of .Net Core, they do not (unless you explicitly configure that you want the legacy behavior); but you can still be notified of them via the TaskScheduler.UnobservedTaskException event.

biznatchio fucked around with this message at 06:55 on Jun 4, 2023

Red Mike
Jul 11, 2011

Kyte posted:

No I mean like:
code:
var bgTask = BackgroundTask.Execute();

(other work)

try {
   await bgTask;
} catch (...) {
   (...)
}
While yeah IsFaulted is non-blocking you can't let go of the task or you risk an unobserved task exception. You could put the task into a queue so you can check it later but that has its own issues.

While yes unobserved exceptions don't terminate any more, you probably don't want them to go unnoticed. IsFaulted isn't necessarily what you'd want to use, but awaiting also won't necessarily do the right thing.

Generally, what you really want to do is make sure that any background task you start (i.e. the outermost Task) wraps all its internal logic in its own try/catch and handles any failure itself, if you're not going to be awaiting it. The same logic as you'd have for something like an event listener.

epswing
Nov 4, 2003

Soiled Meat
I'm still transitioning some .NET Framework 4 projects over to .NET 6/7/etc, question about ASP.NET Core, it appears the ideas of Mvc and Api have been consolidated into one ControllerBase parent class, and for WebAPI functionality/behavior, you decorate the class with [ApiController]. These actions seems to want ActionResult or ActionResult<T> return types, so I can return T in the normal case, and e.g. return BadRequest when something goes wrong.

This is fine so far, however it changes my controller action method signatures from this:

C# code:
public IEnumerable<Apple> GetApples()
{
    return service.GetApples(); // GetApples returns an IEnumerable
}
To this:

C# code:
public ActionResult<IEnumerable<Apple>> GetApples()
{
    return service.GetApples().ToList();
}
Apparently I can't return an IEnumerable directly, I have to ToList all my sequences now. I guess that's fine? Wasn't there some value in streaming a response rather than having to buffer/realize everything before returning from the action?

epswing fucked around with this message at 18:43 on Jun 12, 2023

Potassium Problems
Sep 28, 2001
I want to say that returning a type that inherits from ObjectResult will ensure you don't have to materialize the list & will stream it to the client, but I don't know if that's true or not and I can't seem to find any documentation on it
C# code:
public IActionResult GetApples()
{
    var result = service.GetApples();

    return Ok(result); //Ok method should be on ControllerBase, returns OkObjectResult
}

Potassium Problems fucked around with this message at 18:59 on Jun 12, 2023

Red Mike
Jul 11, 2011

Potassium Problems posted:

I want to say that returning a type that inherits from ObjectResult will ensure you don't have to materialize the list & will stream it to the client, but I don't know if that's true or not and I can't seem to find any documentation on it
C# code:
public IActionResult GetApples()
{
    var result = service.GetApples();

    return Ok(result); //Ok method should be on ControllerBase, returns OkObjectResult
}

This is the generally recommended approach, with the caveat that if it's something like an IQueryable or an IEnumerable that does logic, you're going to have a fun time figuring out what's going wrong on error because it'll end up triggering deep in ASP.NET serialiser code.


epswing posted:

Wasn't there some value in streaming a response rather than having to buffer/realize everything before returning from the action?

See what I said above about the errors though. Streaming a response is great in principle, but either way you always need to materialise your lists/etc as part of serialisation. The savings you'd have in not doing it before you return from the controller are tiny.

If you need the performance and/or have something like a saved raw response you want to return (like e.g. if you're proxying a file you download from a CDN, or it's a mock API), use Response.Body/Response.StatusCode/etc to do your streaming and have your method return Task/void. But then that won't use any of the ASP.NET Core pipeline output formatters/etc.

e: Also be aware that [ApiController] does quite a few changes, and not all are obvious. The docs have a list.

Kyte
Nov 19, 2013

Never quacked for this
Depending on the usage you might do with FileStreamResult from the File(stream) overload and possibly enabling EnableRangeProcessing.

Surprise T Rex
Apr 9, 2008

Dinosaur Gum
Are there any good resources on how people tend to use things like Records/Record Structs, Pattern Matching, and other newer language features in the real world?

Everything I’ve seen so far is just toy examples (“Person(string name)” level stuff), but it’d be cool to see how people are using them to make things nicer.

Semi-related, what are peoples thoughts on stuff like using small private types internally in a class to essentially replace Tuples or anonymous objects? Useful or just noise?

mystes
May 31, 2006

For pattern matching:

In functional languages it's extremely common to define custom union types to cover different cases whenever there are multiple options for something and then use pattern matching on them.

Using them with enumerations would similarly probably be the most natural use in c#, but since I think c# enumerations are probably still a bit less ergonomic (you can't have enumerations of heterogenous types without using separately declared wrapper classes or something right?) and they tend to be used a lot more sparingly in languages like c# than union types in functional languages, that might make them less useful a lot of the time so I'm not sure I would necessarily reach for them as much as in a functional language? I'm not sure I would go out of my way to use it in c# if it doesn't seem natural.

For declaring types vs tuples:

Personally I feel like tuples can get pretty unreadable pretty quickly unless you're using them on like the next line so I'm a fan of declaring types

mystes fucked around with this message at 18:17 on Jun 13, 2023

ChocolatePancake
Feb 25, 2007
I agree completely about tuples. Very useful for a quick throwaway type, but if you'll be needing them any more than in the next couple of lines, make a proper type for it.

Canine Blues Arooo
Jan 7, 2008

when you think about it...i'm the first girl you ever spent the night with

Grimey Drawer

ChocolatePancake posted:

I agree completely about tuples. Very useful for a quick throwaway type, but if you'll be needing them any more than in the next couple of lines, make a proper type for it.

Echoing this verbatim. I've used Tuple for this kind of typing less and less over time and basically only use it now for something extremely ephemeral. Just make a proper type 99% of the time.

brap
Aug 23, 2004

Grimey Drawer
If you have a tuple in a signature that’s getting too unwieldy, you can swap it out for a record struct and have things keep working pretty similarly.

Bruegels Fuckbooks
Sep 14, 2004

Now, listen - I know the two of you are very different from each other in a lot of ways, but you have to understand that as far as Grandpa's concerned, you're both pieces of shit! Yeah. I can prove it mathematically.

Canine Blues Arooo posted:

Echoing this verbatim. I've used Tuple for this kind of typing less and less over time and basically only use it now for something extremely ephemeral. Just make a proper type 99% of the time.

i don't use tuple in production code even if it's a very simple thing. i find code that uses proper types instead of tuple easier to read.

Cold on a Cob
Feb 6, 2006

i've seen so much, i'm going blind
and i'm brain dead virtually

College Slice
Tuples are fantastic for returning multiple types from a single method. Now that you can name them there's no real reason to avoid it as a feature imo

Kyte
Nov 19, 2013

Never quacked for this
I don't use tuples for code that crosses file boundaries or anything public but I find it very useful for returning values from local or private functions as well as from Task.Run and cousins (ArcGIS addin development requires a looooooot of switching to the main CIM thread via QueuedTask.Run) where I can immediately unpack them into locals.

Oh yeah they're also often more useful than anonymous types for LINQ queries that end in a First/FirstOrDefault.

Basically anything that uses tuple unpacking, really.

ChocolatePancake
Feb 25, 2007
I can see the value in returning multiple values from local functions, but I haven't personally run into that use case myself.
It's not so much that I avoid the feature, it's that creating an encapsulating type for all the return values is generally simple and more readable.

Kyte
Nov 19, 2013

Never quacked for this
This might be a bit of a dirty trick but you can have an awaiter for tuples like https://gist.github.com/jnm2/3660db29457d391a34151f764bfe6ef7.

And then use it like:
code:
			var tasks = (
				apiMaestros.ObtenerCuentaAsync(participante.beneficiario_rut),
				apiMaestros.ObtenerEtniasAsync(),
				apiMaestros.ObtenerDiscapacidadesAsync(),
				apiMaestros.ObtenerRegionAsync(contacto.id_region),
				apiMaestros.ObtenerProvinciaAsync(contacto.id_provincia),
				apiMaestros.ObtenerComunaAsync(contacto.id_comuna)
				);

			var (cuenta, etnias, discapacidades, region, provincia, comuna) = await tasks;
At first I was afraid I'd invite the ghosts of race conditions or something but from what I can tell restsharp works just fine with multiple parallel async requests to the same RestClient. (Apparently in practice you can only run two parallel requests at once without some extra configuration but that's more of an internal matter)

Surprise T Rex
Apr 9, 2008

Dinosaur Gum

ChocolatePancake posted:

I can see the value in returning multiple values from local functions, but I haven't personally run into that use case myself.
It's not so much that I avoid the feature, it's that creating an encapsulating type for all the return values is generally simple and more readable.

I think this is my stance on it too, just stick ‘private record struct ButtFarter’ in front of the tuple declaration and it’s basically done.

I’ve used some of the pattern matching stuff recently to allow me to create a single class that takes an IReport interface and uses type patterns to figure out which of the 4 inconsistent inheritors of reports something actually is and therefore where to find the email address of the person we should send it to, but I feel that’s just using a nice feature to paper over inconsistencies in the design where adding a real interface would be a much better solution (but harder because of the number of weird duplicate-but-slightly-different models that such a change would affect)

LongSack
Jan 17, 2003

The only thing I use tuples for any more is in operator ==
C# code:
public static bool operator ==(Foo left, Foo right) => (left, right) switch
{
    (null, null) => true,
    (null, _) or (_, null) => false,
    (_, _) => left.Id == right.Id // or whatever you want here
}

redleader
Aug 18, 2005

Engage according to operational parameters

Surprise T Rex posted:

I think this is my stance on it too, just stick ‘private record struct ButtFarter’ in front of the tuple declaration and it’s basically done.

that's the hard part though: naming your lovely type that exists just to bundle a couple of fields together

Cold on a Cob
Feb 6, 2006

i've seen so much, i'm going blind
and i'm brain dead virtually

College Slice

redleader posted:

that's the hard part though: naming your lovely type that exists just to bundle a couple of fields together

This is precisely why I prefer a tuple like

C# code:
(PaginationResult paginationResult, IList<FooBar> fooBars) GetFooBars(...)
over a type like "PaginatedFooBars" or "GetFooBarsResult" that I will use exactly once in my code.

Adbot
ADBOT LOVES YOU

bobthenameless
Jun 20, 2005

Surprise T Rex posted:

I think this is my stance on it too, just stick ‘private record struct ButtFarter’ in front of the tuple declaration and it’s basically done.

I’ve used some of the pattern matching stuff recently to allow me to create a single class that takes an IReport interface and uses type patterns to figure out which of the 4 inconsistent inheritors of reports something actually is and therefore where to find the email address of the person we should send it to, but I feel that’s just using a nice feature to paper over inconsistencies in the design where adding a real interface would be a much better solution (but harder because of the number of weird duplicate-but-slightly-different models that such a change would affect)

this is more or less where ive used pattern matching the most. something like:

code:

class Base {}

class A : Base {}
class B : Base {}

class Bb : B {}

void dealwithBases(Base foo) {

	 //standard path for all Bases

	if (foo is Bb bar) {
  		bar.logSpecial();
  		//special handing for this one subtype bc it needs a special log endpoint or w/e
	}
}
most places so far I've seen ignore tuples and records overall entirely, the "new" stuff that *really* seemed to hit were when the ??/.? operators and new string interpolation got added in c# 6 (almost a decade ago..). I also tend to be working on legacy/maintenance/upgrades more than brand new greenfield projects so ymmv

the top-level main also prevalent with newer codebases since its the new default I've found, and I've seen a few uses of global usings as well

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply