BrandGhost

Downloading Files in C# - Live Coding in C#

I have some YouTube tutorials to make on several topics - so I'm going to livestream the creation process and explain more things in depth!
View Transcript
sure the feeds coming through okay I want to check on YouTube in particular that's my go-to for making things are working all right so just one moment and we'll kick things off this is going to be a live coding session and if you're watching this recorded well it's not live anymore but um you'll kind of see me get to go through some stuff and Yep looks like we're going through okay great okay so I'm going to be kind of doing what I've done before when I'm doing coding on the stream and that's that I don't have a ton of time so when I'm trying to prepare YouTube videos and create my tutorials and things like that I figured it might be kind of cool for you guys to see how I'm putting the code examples together because I can explain things more in depth if you are watching it live then you can obviously ask questions it can be almost like you're PA programming with me so if you want to be yelling at me in the chat saying likey you're doing this wrong or you have questions just feel free to ask right so it's the entire point of this um technically like I could be going and putting this together faster on my own but I figure this another opportunity for some content to give you some behind the scenes look at stuff and like a teaching opportunity as well so what I'm going to be doing today is building on the last video that I put out which was about downloading files in C and in particular we were looking at when when you're trying to stream data from the internet so say you wanted to download a video file or some big file right um what we want to be able to do is request that file start streaming the bytes but there's a couple of gchas that you can run into and if you're not familiar with streams or you're not familiar with the ways you can go download files one of the big issues is that you could potentially be trying to stream a big file into memory and that's because when you go to call some of these methods the backing stream is going to be a memory stream and a memory stream in C is going to wrap a bite array it's not what you're going to want um so the video I put together talked about being able to uh use response headers red instead of response content red when you're making that request that way you can start almost like lazy loading the stream so you're not going to wait for the whole thing to download but you can start downloading after so there was some feedback on the video uh it seems to be doing pretty well and I figured that means people are interested so that's great but some of the feedback was like Hey like could you show more with this could you refactor this into a reusable class like could we see um you know could we actually see end to endend the file being written out doing some comparisons and things like that um you know one of the questions was about if we go to run this the two variations right one with the lazy loading the other doing the whole thing into memory like is one faster um because I used a timer in the first video and I think people might have been trying to to think that you might download faster one way that's not the point it was really about showing you your time to First Bite so to speak so um I'm going to flip over to visual studio but like I said feel free to ask questions I am watching the chat I'll try my best to to kind of jump over and answer questions as they pop up if they don't happen to be about what I'm going through if you want to ask other things that are C related or general software engineering I'm very happy to answer those things too so if it's not on topic don't feel like you can't ask I'm you know like I said my goal here is in general to help I'm just I happen to be walking through some C code so let me go over to visual studio let me get this flipped over here I think my I got to figure out what's going on with my camera when I flip over an OBS there I am um okay so this is the previous video or the code for the previous video that I had and like I was just mentioning it has two examples that I'm highlighting right now and it's response content red and response headers red the difference between calling these two things is this first example will give us a memory stream and this second example will give us something that's more like a network stream that is lazily kind of pulling the data in as we try to stream it so I figured one of the first things I want to do with this is I'm going to make a new project I'm going to try wrapping this thing up in a little class that we can reuse if you have thoughts about what you want to see on the API for that let me know I was thinking that what might be kind of cool is optionally having the ability to say hey look if we can get the size which by the way is not guaranteed if we can get the size maybe we can say you know what if it's under one megabyte or something or under some you know parameter that we pass in maybe we can just pull it into memory right then we have a memory stream which is seekable because the network stream is not seekable we might be able to do some like that you might want to know when you're requesting to download that whether or not you are going to have the length um just different things like that because the stream API when you ask for the length if it's not supported on the stream it will throw an exception which is kind of crappy so let me go ahead and make a new project over here by the way I haven't thought about um the API and stuff I want to use for this I know that um when I was thinking about putting this together I know that I want to try playing around with some parameters like I just described but I haven't really thought about what's going to feel good for usability so let's call it streaming data dot uh um download download API just as an example I'm terrible with naming stuff but not really the point here we'll go ahead and get this made and then I'm going to copy some of the code that we have from over here um one of the things I did too was I had this stream with length I'm going to I'm going to grab that might as well move it over here just so I have it in this project I am going to let's see have an hdtb client yeah and the other thing too that's not great about this when we go to wrap this thing up I want to make sure that if you want you can use an HTTP client Factory and that way you're not kind of stuck with newing up an HTTP client like this if you're trying to run this kind of stuff on a every time you're NE these HTTP clients up you can uh run into some some nasty situations with uh with socket usage so I'm going to see I might have to import a package to do that but anyway let me let me go ahead and just copy this code and I'm going to start stripping it out we're going to want the URL let me just move the whole thing cool so I don't know what I want to call this yet probably going to be an async method return type this is the already the part where I was thinking like I might want a special type as the return I'm going to start with a stream for now because I don't know yet but at least a stream is coming back off this thing uh and when I don't know how to name stuff I just start with 3 x's and I know I'm going to want a cancellation token because that's good practice and that's all I have for now right I don't really know what's up oh a URL I guess and then I'm going to paste this code in here and we'll start by getting rid of the stopwatch CU we don't need that and we're going to use the second variation which is the response headers red this again is the variation that's going to not force things into um into a memory stream so it will wait other way around sorry it will not wait for all of the content it will start allowing you to stream the response as soon as we get the headers back so let me go do that I'm thinking I want to pull this guy out into a little method so I'll just refactor that out it looked kind of nasty in the video that I created before I was like it's kind of gross to leave it here but we can we can do something um naming convention wise like how do I like to do this I like having something like a try try to get length like that and that means that oops this guy is going to be a buol I don't know why it gave it a a two oh that's because it was already a two up here whoops that's from the video though we'll put that there and what else it needs to out the length so do something like that and here's where it gets kind of weird right so I might change this around to if Tri parse I like doing the negative cases this is just a I should mention this it's kind of interesting I guess I think a lot of people learn in school or whatever uh I've I've encountered this many times where people seem to have a very strong opinion about like single returns in a method and I've seen people write like what seems like pretty ridiculous code like so much logic into one method and they go well no like I have to have the return at the end otherwise it's far too complicated if we have different returns and I'm like you know what yeah you might be right because there's so much code in your method that if you're returning in random spots like you know like 10 levels nesting of like indentation I'm like yeah I would get multiple returns could be pretty nasty but I try to basically reduce indentation as much as possible uce the nesting and then have returns and to me the code reads very nicely that way because if there's ever a situation where I bail out I don't have to keep reading the method to go see what's up I just know that I stop reading if the conditions met and I'm done so generally I like to structure code like that it's not a not a rule but so if we try to parse this and it's not right and I could probably make some of this other stuff a little better I might not worry about that for now um we return false um oh you know what that needs to be there and not have a VAR it was trying to redeclare it essentially but we already have it passed in here otherwise return true and then this is kind of funny because this could be a tary operator or not even I guess um that probably works just as well too so a nice little method for us to reuse makes this part up here a little bit more readable okay so let me make this also not stream to what else is going on okay I mentioned the HTTP client part I don't want to have this here I want to see if I can do and I'm not going to use a primary Constructor um for what it's worth I like using primary Constructors in C and A lot of people are pretty against them because you start to lose that readon ability and it's worth mentioning if folks aren't familiar so what I would like to do here is have a private readon I HTP client Factory and I'm going to have to install the Microsoft extensions HTTP we'll go ahead and do that I love visual studio and then this has to get passed in through the Constructor so we'll go ahead and do that now we have it it here I guess I should give this another name too but that'll come so this way we get a field that's passed in through the Constructor it's marked as readon everyone's happy yay but um what we have is like all of this code I mean it's really not much code if you have a lot more um uh parameters being passed in and uh more Fields like you basically have to like for one piece of information it's it feels like it's duplicated literally across three lines right HTTP client Factory same thing same thing so with the primary Constructor like that feels so nice to me but the problem is the and I I don't know um I I know there's a good reason for this because the net team doesn't just make you know it's not like they don't think about what they're doing but this isn't read only by default and I would like it to be read only by default I would like an option to make it read only by default um or sorry like Market read only but it's not how it works so technically you could write code that does this now almost every single class I make like 90 to 95% of the time if something's being passed in I'm not touching it so if I ever find my self-writing code that's like you know equals new HTTP client Factory you're setting it to null like automatically a weird code smell like it's super rare that I'm doing that however I also like to think that if I'm building software with other people I can't just have only the things I like only my standards um the other thing too is like I used a pendency injection all of the time so I'm I would never be saying new class one I would just be asking for this off of the I service collection or an autofac container which by the end of this video I want to show that we could go drop this onto a service collection and and do dependency injection to pull all these things off so I'm not going to go with the primary Constructor but I would like to but I think when I go to make a video about this probably some people are going to be up in arms about that I'd rather just avoid that but I wanted to explain it okay um so far so good that means we don't need this we can actually ask the factory to create a client for us what else is going on here um oh out length Okay so we should couple things we got to start thinking about now um I want to think about the API that we're exposing here right on this guy so obviously we need a name because that name is terrible um but the other thing is that I want to think about how someone goes to use this and my thought process right now is like when you go to download something it would be nice to know if we like as the caller of this method if we're going to know the length I think that would be super helpful and basically if we do get the length I want to make sure that the stream that comes back also has the length that's why this was important to me this stream here the stream with length which seems silly because it's literally just going to be something that does a lot of forwarding on properties and methods but if we get it I let me walk through this with you for a moment so if we call this method and we pass in a URL to a video when we go to do this part to get the stream because we're using this we're not going to get a memory stream back which is good cuz I don't want to load all this stuff into memory if it's a really big file that we're downloading that means we're going to get a network stream here and that Network stream is not going to be seekable which I can't fix and it's not going to have a length on it either even if we can call this that stream is not going to have a length at least from my experience so far doing this so that's why I want to if we have a length return a stream that also has a length so bunch of stuff going on but something that I'm thinking is like um if we try to get the length and we get it I would like to make a new stream with length like this right and otherwise return the stream um this stream with length thing we're going to have to enhance this because this class when I made it in the previous video that I put online this was kind of just hack together because I didn't finish it I was just explaining like you could go do something like this and I'm already losing my voice okay so we're GNA have to fill this thing out because it's it's not okay um and one of the things in particular is this concept of ownership so when this stream if I scroll back up this is going to between these two methods we're going to have a new stream made for us if I go past that stream into stream with length if stream with length doesn't end up disposing of stream here no one else after we leave this method knows about the stream that's inside to be able to dispose of it later so we need this concept of taking ownership we'll just call it take ownership and that means we'll put a field up here and when we go to dispose which is I guess already implemented so we have to override dispose and we'll say if disposing and take ownership do that this way what will happen is when we go to create this thing up here I want to say yes we'll say with the name I don't like uh I've started doing this more recently when I'm passing booleans around especially if it's just a like a constant value true or false I like making sure that I I use the um the the parameter name uh I find like that's a lot less readable um sure true but but now you have to go like into here to figure out what true means so I like just doing that you could argue the same thing on these other uh things as well but um I find if I have good names on my variables I don't have to worry but um you know another example doing that kind of thing right I'm just not going to this part is kind of silly but if this was a parameter past in or something then I wouldn't have to go provide the name so oh I think I went too far so something like that I think we'll be good and it's still going to be kind of weird I'm not totally sold on this this yet uh forward the cancellation token good call what else we got going on forward the cancellation token um once we start getting into multiple lines like this I'd like spacing things out a little more another thing too um async stuff we don't know where this is being called from if this were in a library and we have a user interface we probably want to be able to use configure A8 false if you are doing something where there is no Schuler that's going to be uh able to kind of flip across threads uh on the return of a task you don't have to worry about that but I'm just in such a habit of doing this because if I go to reuse code and something with a user interface um I just want to make sure I have this kind of stuff in place so yeah it adds extra lines everywhere it's a pretty weird design in general but I just get in the habit of doing it so okay we have the response we have the Stream we potentially wrap it if we have a length and no matter what we're going to return a stream um I still am not a huge fan of of this uh API when we call it so let's kind of see this for a second I'm going to I still need a name for this thing uh we'll call it like or like stream downloader sure and we'll call this something like get get stream maybe to start we'll see we can always name it better later so stream what's going on here can I not do my top level statements well that's weird why not oh cu the name space okay oops didn't see that um so what I wanted to do was do a stream downloader we'll make a new one but as we saw we need an HD P client Factory uh I don't know if I want to start with an i service collection maybe oh it's not called this man what is the thing that makes this I wrote a Blog on this let me this is why I make blog articles so that I can go reference them when I'm messing up give me one sec and I will put it on the screen as well I use autofac for like 100% of everything I do so I know exactly how to do this in autofac but when I'm especially if I'm not an asp.net core I'm like nope I can't remember but I did write this fun little blog article let me get this up here so you guys can see at the same time here we go and we can see this is the example that I think came from the Microsoft tutorial and the reason I wrote this blog was that when I went looking for this answer I was like kind of weird that I'm forced into this pattern of using a host application Builder this might be something oh by the way I have a newsletter if you guys want to sign up for that it's a my little pop up there um I felt it was a little bit like heavy-handed to be forced into this and it might be like good practice in most console applications I guess uh depending on what you're building but I was like uh if I just want a service collection and that's it like what's going on oh I did do it right okay so we can make a new service collection but we need the service provider coming back off so this code here is what I was interested in and can I put the link to that in the chat if you guys want to try this out actually let me just put the whole link to this article in the chat so if you guys want to check that out um that is how I'm going to be doing my service collection so I'm just going to move this over to my other screen so that I can see what's going on okay so make a service collection oh I do add hdp client nice so this comes from the nougat package that I added I'm hoping it's going to work without all of the asp.net core stuff I haven't really seen service collection. add Singleton stream downloader and then we're going to do VAR service provider now let's put it here oh co-pilot knows there we go great okay so what I was trying to get to is seeing what the API is going to feel like and I guess I should go find that video too um one sec it was Sample MP4 so I just went onto Google search sample MP4 this is what I used in my previous YouTube video on this stuff so I'm just going to copy this right so we're going to have a 21 Meg video cool and that's going to be here and we'll see what this API looks like so something like that now again when I call this I'm missing out on the fact if there's a length or not and to prove it let's do this I'm going to write the stream length out so if the if the network stream okay a couple things one if it comes back as a memory stream we have a length but it shouldn't because of the settings that I'm using number two if it has a Content length in the header we should get a length but if there's not something weird going on and this is the exact same as when I made the YouTube video this particular uh file that I'm requesting we don't get the content length so this stream that comes back is not going to have a length on it unfortunately unless something magic has happened since but let's see thanks for the link but now you have a small chat overlay in your stream yeah I I do uh try to keep the chat overlay there if you guys want I can hide it but I like having it so you guys can see what's in the chat and I ran the wrong app um but yeah I like it so that if people start asking questions and stuff is it covering too much of the screen though I can I can shrink it a little bit but it's there let me run this now what am I oh man I thought that the second project I was very distracted I thought the second project was the new one it's this one at the top and it doesn't build excellent what doesn't work oh man I didn't make it an executable oh that's so annoying okay also the stream with length is not complete so even if this does work it's not going to work so we got a client that's great that worked we get the stream we're going to run this call here to see if we get the content length there is no header so we just pass back this stream here and before I run that part stream itself is a Content length read stream from HTTP connection but I don't think it has a length on it spe can't speak specified method is not supported so it did hit the catch block we don't get a length which is kind of unfortunate because I would like to be able to have that or at least no as a caller right there is no stream has length and the only other thing that I've seen really align with having a length or KN is can seek so usually but not always it's not enforced but usually if you can seek you have a length usually but like I said it's not enforced by the API that we have because I have a length that I'm setting here if I go and make this one and the can Seek part I could literally do that right there's nothing that forces you to those things tied together so it's kind of a pain in the butt um but okay we're going to need to do this part this is going to be boring so I'm sorry we're just going to do a pass through for literally everything be cool if there was like a way that automatically did this like you could decorate a class with an attribute and it would just map everything and then you could choose which things to go override but we don't really have that luxury um and I don't know if that's a common enough scenario what am I trying to do here I want to in. position now the other thing is I'm going to see if I can try to find a URL that has a length on it or like a Content length because that would be cool now that I'm saying this when we saw that stream come back that said like a Content length read stream or whatever it was I wonder if that one already has this logic built into it um which would be funny but I don't think it does and the reason that I don't think it does is because I was building something like this for a side project and in fact the stream did not have a length on it even though the content length was passed in the header so maybe but I'm feel a little skeptical about that and hopefully co-pilot starts picking up the rest here thank you this one's kind of weird um I might do this we don't want to be able to set the length at all and we have a dispose method okay cool we'll shrink that back a little bit okay so we are in a situation where if least if this stream gets made we'll be okay but we don't have a good URL to go make it sad TR bone sound w w um let me see if we can find something else what's a good way to do this where do we find should I just search on the internet again let's see one sec try to find some sample MP4s I guess it doesn't really matter if it's a video or not okay let's try doesn't matter what it is as long as it's not super tiny and we don't know so we'll see we'll step through and really I'm curious about this method what headers do we get probably not content length right nope okay well this might be a super awkward video to go make if we can't find something with a Content length can I download this does anyone in the chat have a safe video they can link I don't know if I can trust the chat yet sorry can always open it in another tab I guess but I'm just clicking around here on the internet um no we don't want to play it can I download it oh not doing that we're getting risky here geez okay we'll try one of these guys getting popup ads and stuff now get out of here uh no Andy sorry I'm not building a YouTube download clone I am walking through some C code to be able to uh illustrate that when we try to download files we're not guaranteed to get a length and the challenge when we don't have a length is that well couple things at the beginning when you're trying to just make the request there are settings that you might have and if I scroll down a little bit lower um this is an optional setting it's not the default the default will try to basically download the file into memory and if you're downloading large files that might not be what you want you might want to minimize your memory usage so using this uh property here or this um this argument we can pass in we are able to start streaming as soon as we get the headers instead of waiting for uhet to pull in the whole stream or the whole set of bytes into a memory stream now the challenge though is that that stream that we get back is a type of stream that does not have a length and if you try to ask for the length on that stream it will throw an exception so we're trying to see if we can get a Content length header on the response and if we do have that then we should be able to make it a little bit nicer for us to use but now I need to find a download link for a video that will have that so we'll see maybe this is the one yeah it's uh kind of awkward just trying to find random files to go download but come on no so what kind of headers we got here feeling kind of silly oh there it is nope okay it doesn't have to be a video either I guess um I wonder if I go back to my blog and I grab a image file apparently I need to write my blog from scratch instead of using Wordpress I wonder if my blog just went down I have a feeling literally while on stream my blog has gone down this is why we don't use WordPress and light sale this is the worst combination oh my goodness okay um finally okay so if I go into here can I get this and if I take this link this is going to be a smaller file right so that's not the whole point of this video we're just trying to see if we can get the length now when we go to what I'm hoping to get to and we might not get there is I want to write benchmarks for it and not to it's like writing benchmarks for this kind of thing is going to be a little silly because we're going out to the internet and downloading files it's not going to be consistent but if I can run them over a period of time we might be able to see like memory usage it's less about the runtime but more about the memory usage so uh I'm kind of interested in that but it means we need both flavers we need to have something that will have the uh the content length and something that won't so let's go see if downloading a picture from my blog has it and it doesn't well maybe maybe it never exists and we'll never see it oh what's in here no I want to it's hurting my eyes this text is too small I wanted to see it this way it's a little bit easier interesting well maybe we can go check on the internet when that's set maybe there's a pattern thank you stack Overflow so let's see I know this is what it is okay conent length entity header field indicates the size of the entity body sure applications should use this field indicate oh interesting on and so first Greg thanks for the I'll check I I don't even know if I can say that I don't even know what that is so uh I will check that and Andy has an interesting point maybe content liketh isn't available until the client attempts to access the body very interesting I never thought about that I never thought about that so let me first of all um thanks to both of you I'm going to search okay I'd never heard of hner I wanted to make sure I wasn't about to get like hey go to like I don't know something real bad and then I click it and then not in good shape so hetner can I just search like test files oh nice okay let's see so we know that none of these work so that's okay but Andy has a very interesting point so no headers coming back still so that might be the case um oh content length it's there am I just very silly my cursor is too sensitive apparently I for context I I guess last week or two weeks ago I switched over to my gaming machine for doing streaming and video recording because my laptop I've been fighting with audio issues for over eight months and bought like a whole new setup doesn't matter um apparent there's just like literally Hardware problems with my Alienware laptop and nothing's going to fix that unless I buy a new one so um I'm not doing that so I just switched over to my gaming machine but now like there's little quirks like my my mouse is like too sensitive and I'm not paying attention that kind of stuff so okay so it's not content thing what's up here I'm pretty sure it's supposed to have a dash and why can't I see it now let me pull this back up I'm positive I saw it Oh no is it right on the response oops oh my goodness I was accessing the wrong thing this whole time well there you go [Laughter] that's this is a great learning opportunity for everyone this is why if you're PA programming which technically we're doing that right now even though it might feel a little bit one-sided when you're par programming you can catch all sorts of dumb stuff like this so that is my fault so there we go so maybe Andy is partially right here cuz accessing content at least gets us the headers um but yeah that's that's my bad okay so can I do this without recompiling yes super cool feature there we go has a length Best Day [Laughter] Ever and we can parse it out we get a length cool now we get this other stream made okay thank you Greg thank you Andy um I don't know if I would have gotten there if you guys hadn't pointed me in that direction so I appreciate that okay and that actually means my I feel this is always a crappy thing when I do this and like that YouTube video is out there I can't go and edit the YouTube video right which sucks CU now it just lives there for forever and someone's going to and you can go do this now if you want go comment on my video and be like you're such an idiot it's obviously on it's obviously on this other property um anyway we'll go make that stream right so now H I left this in here and I shouldn't have now we go do this if I check the console we get the length right Best Day Ever um but it's still not a great API for us and it's not a great API because if we didn't have the content length for any reason cuz it's not guaranteed that it's set there if you I know I only showed it briefly maybe I still have it up here um wherever it was on here applications should use this it is not enforced it's not enforced applications should use it so we can't just assume it's going to be there and just like we don't want to assume it's there when we're going to use this stream object I don't just want to go ask for the dot length and it's not supported it doesn't have a like a has length property which is very unfortunate we could add an extension method and this would be terrible by the way like an extension method that says has length and then it does a try catch around trying to access length not not a good time I don't want to do that um so the way that I was thinking about doing this was having a result come back from get stream and doing something like and this isn't going to be perfect either when I started this stream I kind of mentioned I hadn't thought through the design of this yet so this is me trying things out right so I was thinking of doing something like a um stream result and then doing the stream and then doing something like the length on here that was kind of my first thought and that way when you go to call this API you're actually doing this and it's not that and it's not even the length I guess I don't want that I want BU as length I think that's what I want to do so this is going to make some things look pretty gross inside here so please bear with me as I try to explore this I want to do something like this that's my new preferred way by the way I don't like declaring um I I use VAR all the time as you'll notice right use it all the time but if I'm newing things up I like to put the type name on the left and then just use the shorthand syntax on the right because me doing this oops just feels silly now it's literally the type in two spots so um some people hate having VAR here right and then doing the type on the right I just it's my preferred way to do things now I mention this because if you're wondering why I'm doing it it's just personal preference if I were working and coding this on teams I would be talking with my team about the standards that they want to use right I'm not going to die on a hill trying to fight for using VAR if people hate it I just don't like doing stuff a lot and yeah big fan of type type equals new we read left to right exactly um so the reason like I don't end up putting stuff like this here is just like for a lot of it I I rarely have situations where I'm doing this kind of thing and I'm like man I really wish I knew exactly the type was like I almost never need to know personally it just doesn't seem to really inhibit my understanding of code that's why I was saying if other people on the team are like dude like absolutely not I hate that then I'm like cool like the readability is important and if that's affecting your ability to read the code we're working on I will change what I'm doing so um that's just little little tangent um okay so we have a stream with length in here so I'm focused on this part that I'm going to return out of but that means I want to return this kind of thing now this is where it gets weird because I this is going to feel pretty gross I don't know all of the types of streams that um this thing can return I don't know if it tells us kind of doubt it memory stream okay so again we we're kind of poking inside I always think that if you have to go look inside of a method like you're probably about to do something gross and spoiler alert I am about to do something gross so I was thinking that the challenge is still I don't know if there's a length and I can't just trust if it can seek maybe I can I don't know maybe we should let's let's search that maybe that's like a an unspoken thing let me open a new tab here um here we go see everything's on stack Overflow therefore in all of the large language models but okay additionally from the docs for stream can see if derived uh from stream sorry if a class derived from stream does not support seeking calls to length set length position and seek throw and not supported exception this doesn't it doesn't say it the other way I feel like it tells us if it can't seek oh sorry no I guess no it does say it the right way it does say it the right way if a class drive from stream does not support seeking which means if we check it and it says false call to length set length position and seek throw a not supported exception okay so that's good to know but it feels kind of silly so I maybe I don't need any of this stuff because we can just check the can seek um now here's the I guess there is a bit of a weird thing here I did illustrate to you earlier that um what was I trying to show exactly so if we have we're basically When We Make an instance of this class the stream with length I can set the length because I know it but they're actually saying in the uh msdn dogs apparently according to stack Overflow and I trust it they're saying if can uh can seek is false these are expected to throw but it's like I have that information that feels gross to me like why would I not indicate it on my stream that we know the length so I guess this is a bit of a a crossroads right I either go against the recommendation in the docks which to me doesn't necessarily line up with the API and that feels bad or I go ahead and I just do what the docs say and I don't like that um but we're at a crossroad so if we're going to play by the docks that means we don't need this thing at all we don't need it and I'm G to kind of I'm going to walk down this path explain some things and we'll we'll kind of chat through the the implications of this so um stream result here instead of has length it will be the length because apparently we're not supposed to use the stream length if it can't be uh it doesn't support seeking I hate that okay um that means here maybe this should be nullable as well so what happens if we have a stream that doesn't have the length we expect a null on the length it's already like this is already more gross I'm going to go down this path if you have thoughts about what you're seeing as I type it feel free to share because like I already don't like it but I kind of want to see it in use before I make up my mind I'm going to comment this part out it's on my clipboard though so let me because I don't know I might want to come back to the stream thing I'm not sold on it yet that we need to go follow those rules it just feels really terrible to me okay so if we do this that means we should be able to say stream here and check if it has a length we'll do that and this is actually the length now right what's going on oh it's not named I guess there we go okay so if we have length otherwise no we could use a negative one I don't know awesome thanks Andy I appreciate the support cool okay so we're going to go down this path try it out see how it feels I am speculating I'm not going to like this though this is no longer using that it's a stream result and how that looks is we would have to say something like stream result do length as value and then stream result. length. value like it's not not great um and then you could do I wouldn't I probably wouldn't even write it like this actually it's too too nasty so so I probably just put in an if statement like this come on co-pilot no there we go look at that it knew so this might be workable stream result we can check the link I hate the nullable long like that that part to me feels just really this feels really gross to use um let me go run it oops don't need that anymore I just wanted to see what it yeah so it it works right but this just feels feels gross the other this is what I wanted to get to though the other part that's terrible about this is that if you are working with streams so there's lots of classes that either exist or you might be writing and you're working with a stream and this is literally the entire reason I had to go do this is that I needed to know the length of the stream I was working with I didn't care to seek I'm downloading something from the internet I'm trying to send it somewhere else and part of my process is that I require the length so that means in my API that I'm dealing with internally to my system what I would have to do is pass around not only the stream but also a length associated with that because apparently according to the docs if we can't seek we're not supposed to set the length I'm just I'm not diing that I feel like that is not that's not okay so let's go put this back we're going to break some rules this would be worth talking about when I make the actual YouTube video that's a little bit more succinct on this again we're going through all the learning right now um I will mention because I learned that today about can PE and the length I figured it was probably implied because it seemed to be consistent but like I'm not I'm not down with that so we're not going to do that we are going to have a stream here and has has length we'll stick to that and has length is true there and what I'm going to do we don't have to call that again this is where it was going to look a little bit gross um wow I can't spell has length Okay so if the stream can seek it has a length that's because apparently we have the only stream that's not inside of net that is going to have a length and not can seek at the same time so we'll go up and change this oh sorry that is still a stream result but it is a little bit nicer to use I think because we should be able to do something like this um uh this is kind of stupid this is just this is just the string interpolation part so um so we can check if it has a length now right if the result came back and it has a length we know we can access length otherwise my goodness my spelling is not okay calls two string on that where am I missing I can't see where I'm missing my stuff does it need I don't know why that happens string interpolation isn't a big fan of you doing that kind of stuff without extra parentheses in there I don't know if you caught that but if I take this off and this off it can't figure it out it can't figure it out but if I put these back in it knows even though it's inside of the curly brace it's kind of interesting um okay so we should be able to do this because we trust that coming coming back from this method that if it said it has a length then we can read the length off of this so running this again right that just works I much prefer this personally and if I kind of explain in my own system where this was coming up a little bit more what I started to do was that stream with length class that we saw I basically started enforcing in places that needed a stream with a length like you had to go make a new instance of that class and because it can wrap other streams it was very convenient because I could say hey look on my API let me just show you it's probably easier than me trying to talk with my hands at you on a stream so what I started to do was something like this I'd have I have something else right and it has a method on it that's like public void do something and it would have taken a stream and we're doing some stuff in here and at some point it needs to access the stream length actually I have a great idea okay so this is the idea so it has a method like this right it's doing something and it needs to be able to access the length but then what I was running into was with my downloading everything that we just saw right if I go back to here because the stream that comes back from this is not guaranteed to have a length in fact it just doesn't have a length which is annoying because it doesn't and that makes sense now because it's uh as Microsoft is saying in the MSD OCS if it can't seek and you can't seek on the network stream it won't have a length just by default so what ends up happening is we pass in a stream here and from our perspective of this method we don't know it could be any stream it could be a file stream it could be a memory stream it could be a network stream like we were seeing when that happens if we go to access length it blows up now I know based on msdn docs they are saying if you can call can seek you should be able to be protected but in my case again I'm just bringing up this use case I don't care about seeking I literally don't care I just want to be able to have the metadata to know the length of the what I'm downloading that's all I care about and as a result if I follow the msdn docs it means that I can't do that I would literally have to go do this kind of thing right I would have to do that and guarantee that someone can pass in the length so my way around this was basically to do this um stream with length and the reason that's important for me is that I know that if I'm accessing this class it's guaranteed to have a length on it that's set guaranteed 100% all the time and that's important because now I can have more trust and confidence in what I'm building inside of here because I'm sort of forcing things to go down a certain path now you might say well Nick that makes it harder to call this thing and you're right it does so let's get rid of this and we'll do some other system component right we'll make a new one we'll call it say okay well see like Nick you can't call that now you now you have to go do this whole other thing and look co-pilot just knows isn't that great so this is how we would have to do it but I actually don't mind this um I actually kind of like this a lot and that's because in my spots that I'm needing this length I just know that I have a type that's going to work this isn't I'm not saying that this is how you have to do it all that I'm trying to do is walk you through some different examples of like what you might want to consider when you're writing code right so you can I'm making it a little bit more work to call this thing and we could even shorten it right this is this is a little gross but you could do an extension method on this thing and how would this look so what I wanted to show you I'll show you kind of the long Gross Way first and then we can talk about something else so we might be able to say if um stream result stream is if it is a stream with length can we do I just do that I think I can do that cool okay so yeah I know it's looking gross but bear with me for a sec what I'm saying is hey look if we have a stream that's coming back and it is already a stream with length then don't do anything just leave it you can cast it you know that it's going to be the type you need otherwise we're just going to wrap it we're just going to wrap it and that way we can take the result off of the stream result and actually yeah this this check all makes sense otherwise it's a zero that actually doesn't make sense so we would need to throw an exception or something so and just to explain that for a second because that's probably a little confusing because the turn are operator um we actually can't or don't want to do this kind of thing we don't want to go make a stream with length with a zero length it's defeating the whole point so we'd have to throw like some exception to say like it's not working like you can't go make it this way but now we can go clean this up a little bit because I think we can go make an extension method that basically does this so I would like to do do I need an extension method do I want to put it on stream yeah let me do it on stream by the way I'm I'm thinking about these these things like on the fly so sometimes you'll see me go down a path and I'm like nah that was stupid but that's normal that's how I code right I'm going to try things out um I am the kind of person that when coding I like to go down certain paths I like to it might be a little bit wasteful but it helps immerse me into what I'm writing some people might say like I'm going to spend a lot more time uh just like thinking about how I want to design stuff and some things I do like that like ESP like a system design I usually step back a little bit but sometimes for apis and using Code I just like want to code it so I can try it quicker the sooner that I can get a feel for how it looks the less time I spend in general so um it maybe I shouldn't say less time I spend in general less time I spend overall because I've gotten to try it and I didn't say hey I'm going to plan all of this out ahead a Time stick to a path and then I start using it and I'm like man this feels like garbage to use so I like getting in the code and messing around okay sorry I was falling apart okay so sat class we're going to do some stream extensions uh I will describe extension methods for you watching on the stream if you're not totally familiar I don't know the whole audience some of you obviously know about this some of you may not so it's worth explaining a little bit um extension methods allow us to attach other methods onto types in the next version of C I guess trying to figure out if it's net or C that technically has this but anyway it's coming up we're we're going to have more of a first class like extends kind of functionality and there's already videos and stuff online about this um pardon me if you're watching my videos you're almost guaranted he'd be watching Nick chs's videos he's already made videos on this and I don't know I haven't checked the net team might have already published stuff on this because um build was the other week and there's a ton of content coming out of that so I am going to be using normal extension methods but I'm just kind of adding some context here that the the capabilities we have coming up are going to be looking different for this sort of thing so what I'm thinking about doing is having a stream stream with length this needs to be static and what we're going to do we give it a name that's stream with length and we need this sorry I was just trying to read if co-pilot was doing what I want if I could just press tap I don't think it is quite yet so here's what I was trying to figure out um okay so I just wanted to comment this so I can have it as a reference so if the stream we have already is oops so if it is a stream with length already just return it this just turns into a cast that's nice we don't have to go make another stream with length to wrap a stream with length it's just literally silly so just return it otherwise we are going to make it so what does it need well it needs the stream that we're passing in oh this reminds me why I wanted to structure it a a little bit differently I want this to be a try method I don't like throwing exceptions I find as soon as I have to throw an exception code I try to redesign my API like almost immediately I don't like doing it because I want how do I phrase this I want um I want as much sort of control flow to be guided by uh result types or booleans like data rather than exceptions as much as possible I want to avoid throwing exceptions to guide the application this whole the whole point of this thing is to be able to be helpful to get us a stream with the length if we can if not I just want to know that we cannot that's the goal I don't want it to say this is an exceptional situation you should you should stop the program that's like when you throw exceptions that's what you're indicating the program should not run anymore something's wrong I know we can put try catches in place but that's the point I don't want you to have to put a try catch around this thing just to be able to check whether or not you can make one of these so if I this is why I wanted to pull into an extension method because if I scroll back up the fact that I wrote this if you recall as soon as I wrote it I said I want to put this into an extension method because I'm going to try to clean this up which means I am going to make this a Boolean return type um try as stream with length I don't like that um I don't have a better name yet though so the other thing too is that I I'm using the naming convention and the out sort of uh standards that we have built into the rest of.net but I I have my own result type so when I'm building my own libraries I would just have instead of an out parameter this would be a result type that I have just elaborating a little bit so stream with length is here so that would mean we would set stream with length to be casted why doesn't like it oh it's because this part's throwing it off okay so then we would say if it's not we would have to check if you can seek so co-pilot knows I don't does anyone else have this problem that's a I should redo that this is what I have to live with with co-pilot and I've seen a couple of other people on Twitter say this but watch see how it looks nice and formatted I'm going to press tab like what is that why is it doing that it's absolutely outrageous so every time I'm using co-pilot I have to go back and do that I was just doing it out of uh out of uh I don't know like a muscle memory right like I should pause and see if you're wa if you're watching this now let me know and if you're watching it recorded let me know if when you use co-pilot if it makes these ridiculous indentations I don't understand why that's the case anyway um it's been driving me nuts so if we can see if we can make a new one of these because according to the docs we should be able to access the length should be otherwise this thing's going to throw so to be extra safe we could put a TR catcher on this I'm going to come back to that in just a moment otherwise we will say stream with length is null return false so I am going to put a try catch on here this is probably making some people's skin crawl sorry um if you call my method and it says try on it in my opinion this thing ain't thrown any exceptions not happening um I actually have my own patterns that I use and my own code that basically change methods into big try catches if they say try in the name it's basically going to enforce that no exceptions getting thrown um that way I can work with my result pattern and check for exceptions and errors and things like that and I find again personal preference that switching to that versus just calling stuff and having to do try catches everywhere I basically build the TR catch into the method itself um with some helper classes and things like that actually this a good reminder I should ask my friend who does a lot of Roslin stuff if uh I bet you he would have a really good way that if I marked something with try in the name like this that he could tell me how I could use Roslin to to do something fancy there but anyway just wanted to mention that if I am putting try out the front in the name I don't expect that my uh method is going to throw any exceptions so to be even safer I would wrap this whole thing in a TR catch but I'm not for now cuz that shouldn't ever throw and that should never throw either it would be kind of ridiculous so it's on the part that needs it technically can see could throw technically and if you don't believe me like there is nothing stopping from someone making a stream like that that it won't be in the buil-in stuff I hope uh but you know there's nothing stopping from someone making a stream like that so I actually will go ahead and move this out here will this format nicely there we go what am I missing here we go too many curly braces okay so now we have a stream extension method that was a lot of work just for an extension method and we could do something like so stream resolv I guess we can't put it there we would do something like this stream res.st stream try as stream with length we'd have to do some type of handling and see how I can use an if statement here instead of a try catch I love this that's the whole point with the uh the try stuff right I build it into the the language like it when I say language I don't mean into like C obviously I mean into how the code reads I want to be able to use if statements instead of TR catches wherever possible in this particular case yes I had to bury a TR catch in here but I try to hide this kind of stuff so that callers don't have to think about it and that way if I in here needed to return some type of error situation that's not truly an exception worthy of cat or crashing the application I would have a result type that had an exception on it that way I could go check the error that comes back anyway we don't do that right here but that means I could do stream with length here and I think that feels pretty good to me I'm starting to like that a lot which means oh one thing that's kind of silly is that I guess this is where people talk about discriminated unions um if I had a result type in this situation here um see how there's a squiggly under stream with length it's because the type which I'm using VAR here and if I put stream with length here you'll notice it also gets a squiggly it gets a squiggly because it's not quite right it's a nullable stream with length and that means technically I need to null check it but that's silly because the way I design this is that if you have a true coming back it I can't guarantee it in code that's the hard part but what I'm trying to do is suggest that it must have a value assigned so um a discriminated Union would help us because we would be able to say that we either have the stream coming back or not and not have to do this weird thing where we check for a true it's true but we still can't trust that it's not null sucks maybe someday um net team is very smart I'm sure they'll figure something cool out so this the way that we get around this is is this little guy we put an exclamation mark and we say hey we know we know it's not um I don't know if we can do it can we do it up there no you can't it would be nice if on an out parameter like this I could say like I know that it's not going to be um anyway I'm going to leave the squiggly there because technically my code does not guarantee it based on the API but I think that this should all work fingers crossed there we go right so we didn't change much we just uh worked on the ergonomics of calling this thing so hopefully it feels a little better in my opinion it does um but that's not going to be what everyone agrees with right I am going to wrap up this stream but I wanted to you know use this as a kind of a a sign off moment to talk about that part in particular which is I just walk through how I would like to design code that's my opinion um someone might be watching this whether it's live right now and you've been fuming and you're like I you're maybe you're still writing a message to me that's how much you hate this um or you might be watching it recorded and you're going to leave me a comment or you're thinking about this and you're like I would never write it this way I hate everything about this I would throw exceptions I would uh listen to what Microsoft has to say about the can seek and the length property that's totally cool that's totally cool my goal here is not to tell you that you must do it this way um hey Gerson thank you I appreciate the support um but yeah it I'm not here to tell you like you got to do it this way I think you are missing the exclamation mark in the if plus a return then it should not be null for the analyzer in the if plus a return um is it inside this method like you mean there because I don't think that it will no still because I think it can only see it based on on the API itself not the internals like we as humans know that and that's why you could go put an exclamation mark here if oh I see what you're saying sorry that was that was actually a bug it still won't know though I don't think thank you um so yeah that was a bug but the issue is that the analyzer still can't know I bet you the static analysis could be smart enough to actually figure uh this part out but um it's going strictly based on the API I believe so uh as a result it's unable to which is unfortunate but thank you that was act that was definitely a bug that needed a exclamation mark to say not if this worked so yes the my goal here is to show you that this is how I like to kind of explore building out my API um kind of walking you through how I like to think about my flow control and things like that but it's not to say that it is the right way um oh I think I was basically making comments about people like raging about what they're seeing here but the the idea right is that you're going to have your own opinions and I want you to be able to have those opinions and I want you to be able to work in your teams right so you're if you're watching this and you feel like you're very uh triggered or unhappy about what you're seeing and like I would code it a different way like all of those emotions and that frustration that you're feeling like there's nothing wrong with that because you're allowed to have your opinions about things but what is important is that when you go work with your teams at work is that you don't express things that aggressively you can have your opinions be known you can work with other people on the team and say hey here's here's why I wouldn't write it like Nick here's why I would use exceptions here's why um I wouldn't use the try pattern and all this stuff like you can have your opinions and when you go to work with your team make sure that you're listening to what they have to say too right because everyone has an opinion you can't like it's going to sound funny you can't tell me that what I coded here is necessarily wrong aside from that um you know the can seek with the length thing like according to Microsoft they're saying that would not be the right thing to do but otherwise in terms of the style that I'm using this is just a style it's a preference right it's not a right or wrong thing I'm not saying it's better or worse I'm saying this is what I like so I want you to think about that when you're working with your teams because there's going to be other people with strong opinions too and you should listen to them and you should talk to them and it's okay to have a heated discussion but you need to be listening to the other side of it because you can learn so much when you're listening to other people that have completely different perspectives you're allowed to disagree on things right but if never listening and trying to understand what they have to say it's not going to be a fun time as a software engineer like just get ready for many years of being frustrated but instead if you're just willing to listen you can speak up and share your ideas but make sure that you're listening to what other people have to say and I think that you'll be in a better spot to move forward on things so I think that's it I didn't get to benchmarking stuff unfortunately uh I am planning on having something like we just saw in here as a video for early next week um and I hope to do the benchmarking stuff as well the benchmarking is like I said earlier if you just join the stream the benchmarking is going to feel kind of silly I'm not trying to prove performance here in terms of uh runtime performance we're downloading files off the internet I don't control any of that stuff my Comcast could you know halfway through the benchmarks decide no thanks right no control but the part that we have some control over is the memory and it would be really cool to see that if we do this version or we can check the length and try to go with the non-memory stream versus memory stream situation we can hopefully see that the memory allocation that we're doing is lower when we're just streaming directly and not trying to put it all into memory so I think that's it but those two I'm going to split into two videos one kind of like what you just saw today but more succinct you got this see a little behind the scenes of how the codes put together and then the Benchmark stuff and so Gerson thanks um yeah follow me uh in all the places if you have questions please reach out um Greg thank you for the comments along the way and yes I will try to do more sessions and with that said um please yeah reach out to me if you want to see different things either on YouTube videos or done live let me know um I I try to make this very clear to people that like literally all the content I put out if I don't have ideas for what you want to see I'm basically just making content on stuff I get stuck with or stumbling upon and I go oh that would be handy that's how I write a lot of my blog posts that's how I a lot of the videos come to be unless people are giving me ideas so for example last uh for this last newsletter I put out I had someone reach out to me on LinkedIn and they they said hey like thank you so much here's a bunch of questions I have literally two new newsletters worth of material to put together to answer this person's question questions sorry they're going to be the topic of my live stream coming up on Monday Monday nights in Pacific time I try to do more General software engineering so I'm going to be answering all his questions and I'll probably do the other half of his questions the following week so for coding stuff if you want to see me go through things just let me know like I'm happy to try and help uh it makes my life easier if you let me know the type of content that you want to see so um just let me know all right I appreciate all of you thank you for for tuning in hopefully this was helpful um sorry that it took so long to find some videos to download with content length because it had nothing to do with it it was just me being an idiot but um there you go pair programming right okay thanks folks appreciate all of you and we will see each other soon take care enjoy the rest

Frequently Asked Questions

What is the main focus of the live coding session?

In this live coding session, I'm focusing on building a reusable class for downloading files in C#. Specifically, I'm demonstrating how to handle streaming data from the internet efficiently, avoiding loading large files into memory.

What are the differences between response content read and response headers read?

The main difference is that using response content read will load the entire file into a memory stream, while response headers read allows for lazy loading, meaning you can start streaming the data as soon as the headers are received without waiting for the entire file to download.

How can viewers interact during the live session?

Viewers can interact by asking questions in the chat. I encourage you to share your thoughts, ask for clarifications, or even point out if I'm doing something wrong. It's meant to be an interactive experience, almost like pair programming.

These FAQs were generated by AI from the video transcript.
An error has occurred. This application may no longer respond until reloaded. Reload