❔ Web Services - Beginner
Hello, I'm in the process of learning Web Services. I have successfully followed the tutorial (https://learn.microsoft.com/en-us/aspnet/core/tutorials/min-web-api?view=aspnetcore-7.0&tabs=visual-studio) and had it running, and everything works fine.
I would now like to explore a bit more with Web Services.
My first question is the following:
This is the default code that comes with the
Program.cs
file when I create a new ASP.NET Core Empty Project.
If in my browser I do localhost.../
I will get Hello World!
.
My goal is to be able to pass and interpret parameters now.
What changes to the code would I have to make, If I wanted to check if the parameter, for example name
was passed, so that the code now does Hello <name>!
?Tutorial: Create a minimal API with ASP.NET Core
Learn how to build a minimal API with ASP.NET Core.
172 Replies
This is what I think I would need to do:
$tias
but yeah, that looks about right
Well I did 😅 And I'm not sure I got the hand of the parameter thing
Hello {name}!
This is the output
app.MapGet("/{name}", (String name) => "Hello {name}!");
ah you missed a
$
This is the code
Oh right
also, prefer the
string
type over String
they are the same, but the string
can't be changed by scope
its just convention to use the lowercase alias 🙂Noted
So, for multiple parameters, I would repeat the pattern?
Yes
More or less. Http parameters can come in a few different forms
You can also inject services, might be a nice topic to look up
what you have right now is a "route parameter"
Really depends on the context but you can pass a lot. Query parameters, route parameters, body objects, services
http://localhost/Steve
will print "Hello Steve"You can also split the method you made into its own controller which could be more scalable and easier
query parameters look like this:
http://localhost/?name=Steve&age=28
The end goal would be to do something like
website/name=wasd&age=5&address=Something
and then you can also have your request submit a payload (aka request body), which is not valid for
GET
requests 🙂
okay, then dont add them to the routeI see, how would I iterate thru the parameters I pass then?
app.MapGet("/", (string name, int age, string address) => "Hello {name}, you are {age} years old and live at {address}!");
Ah just put them in the function, okay
well, AND the function signature 🙂
Yep I corrected after writing 😅
So what would happen if I did not pass any parameters, or if One of them was missing? Would I get a 404, would they get default value?
query parameters are optional by default
thats their intended use
I see, well, the service kind of needs the parameters to be passed, else it will be kind of useless. Technically they will always be passed, since the only thing that talks to the services is code, but out of curiosity, is there a way to check if the parameters were passed?
They will have their default value.
name
and address
will be null, and age
will be 0. You can make them required, but then you need to add a custom class with the required
attribute: https://learn.microsoft.com/en-us/aspnet/mvc/overview/older-versions/getting-started-with-aspnet-mvc3/cs/adding-validation-to-the-model.
Your method would then be this:
app.MapGet("/", ([FromQuery] RequestClass request) => "Hello {request.name}, you are {request.age} years old and live at {request.address}!");
Note if I don't add the FromQuery
, .NET will look in the body of your request, which is wrong.^
I see, thank you for providing a link to the documentation
I will try and make that work
Curiosly, currently it requires the parameters
Ah, it respects nullable reference types. Didn't know that.
thats neat.
so you're getting 400 bad request
Now I don't know how to interact with it hehe
well you need to pass the querystring
Doing
https://localhost:7232/name=WASD
gets me 404'dyou forgot the
?
right
That was it :)
Would I still need to follow what FusedQyou posted?
its recommended
but you dont need to
I see, I'll do it for learning sake
So I tried something that failed
So I would have to always implement a
TryParse
in my class?try
[AsParameters] Person p
That did it, yep
I also noticed that the parameters are not case sensitive
correct.
or rather, they should be, but accept both
camelCase
and PascalCase
versions
so Name
and name
should both work, while NAME
should not, iircAny combination works actually
At least on my machine
¯\_(ツ)_/¯
okay, maybe I'm confusing it with the json defaults
Okay, so I can now successfully pass parameters.
This is like 30% or my goals for today this is nice
The next thing I want to do Is the following
I need to access a website (passing it the parameters I recieved), get the HTTP repsonce of the website, parse it (I recall you mentioned something about this the other day), and return the parsed result in JSON
The previous code used something called
HtmlWeb()
and HtmlDocument()
Right, this is the http proxy
Are they both the way of doing this?
Or are there more modern approaches?
I have no idea what
HtmlWeb
is, but that all sounds ancientYep :)
As a start, lets just make a http request
Apparently its from the
HtmlAgilityPack
Okay, thats fine but I personally greatly prefer
AngleSharp
its faster and more robustI would need to use NuGet for this?
yes, same as HAP
HtmlAgilityPack is also a nuget
Did not know that
I will see if I find something that sounds like
AngleSharp
but lets ignore that for now
lets make the request first.
Sure
step 1: you need to add a HttpClient(Factory) to your service collection
builder.Services.AddHttpClient();
That is a factory for Http requests, correct?
Requests are objects here, i think
no, its a factory for http clients 🙂
Oh
it handles all the complexities of creating and disposing of them for you
makes life much easier
Noted
now, in your route handler
lets request the factory
add
IHttpClientFactory httpClientFactory
as a parameter in your route handlerSo I'm a bit lost in terminology here
When You say route handler, what do you mean?
thats the
MapGet
lambdaI see
the function you are declaring
So you also say as a parameter
So I would have a
Person
and a IHttpClientFactory
in the parameter?yes
you can decorate it with
[FromServices]
if you wantSo much magic happening behind curtains here
yes, minimal APIs are... very magic
I personally don't use "raw" minimal apis like this
You use Controllers?
for some older projects, yep.
but new stuff, I use FastEndpoints
which is a library built on top of MinimalApis
Interesting
but for now, this is fine
So when I access the endpoint, the
httpClientFactory
will be magically instantiated with something?it will be resolved from the service provider 🙂
I see
Supported binding sources: Route values Query string Header Body (as JSON) Services provided by dependency injection Custom
btw, this page is a godsend: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis?view=aspnetcore-7.0
Minimal APIs quick reference
Provides an overview of minimal APIs in ASP.NET Core
it has pretty much everything you need to know about minimal apis
I'll definitely give it a read, thank you for sharing
okay, so we have the factory in our handler now?
We do, yes
great. Lets get a client!
var client = httpClientFactory.CreateClient();
So in this situation, I assume we will make a Single client, and the client itself would make the request, becasue we cant have a request wiithout a client, did I get it right?
we cant make a request without a client, yep
asp.net doesnt itself know how to make http requests, it only kjnows how to respond to them 🙂
its a server, after all
I see
So the HttpClietnFactory takes care of all the http requests we make
and responces it recieves
all we do is give behaviour to our route handlers
🙂
oops
Let me try this
The HttpClientFactory makes Clients, each client takes cares of the requests it makes and responces it recives
Better?
It's fine to use Clients in a scenario where the session is irrelevant?
Isnt it a bit overkill, or is there no way around it?
you need a client to make a request
the whole point of using the factory is that we dont want to care about where the client comes from, when its created, disposed etc
we jsut want a client
Okay, noted
a client isnt an ongoing session, its just something that can make http requests
It isnt? Interesting
so, now that we have the client... lets make a request.
Out of curiosity, is there some website online made for this? Something that we can practise sending requests with expected responces?
sure
for HTML responses, any static page will do
lets start with a great webpage: https://vecka.nu/
it just shows the current week number 😄
That is perfect!
so, to get the entire webpage... we just do
this will return the entire webpages source html as a string
you can then feed this string into HAP or AngleSharp to start parsing it
AngleSharp has some ways to load webpages built in, which would remove the need to do this yourself.
btw, since you said this needs to be fast, manually parsing it might be a lot faster than using a HTML parser, if the data is easily parsed.
That might be the reason they make a Parser from scratch
Would have to check with the previous maintainer
(im asking im rm :) )
if the HTML is fairly straight forward, you can optimize a lot by making assumptions (that AngleSharp can't, since its a general purpose parser)
Well the Parser itself is a bit weird honestly
Okay so the flow they did was
The HTML response was loaded into a HtmlDocument
(from the HtmlAgilityPack)
and they they did parsing like this
Stuff like this to get the values
thats not weird at all imho, thats just your standard XPath query
but for HAP to do that, it needs to parse the entire document and build up a tree
The weird was not refering to that flow, it was referring to another thing they called a Parser that is soemthing else i was mixing up, my bad
So would I be able to do that with the technology you mentioned?
It still searches for something
So no real optimization here
They dont really assume the format of the data
They then load that into a object
and in the object they have a
public FormUrlEncodedContent ToFormData()
which I assume its to put the information on JSON format
So that they can return the object in the end and magic happensIm just saying thats a possible avenue for optimization
but you can absolutely get started with using HAP and/or AS directly
I'll note that down, maybe in the future I'll talk to them about it and see if I get approval to do that, thank you for pointing that out
Currently they just want me to split the services and gave be a bit of freedom of the technology I can use
However
Remember talking about IIS
and that you advice me to use Kestrel
Well I brought that up talking to the boss, I did some research and sharing it with him
And he told me It would be hard to convince him to change to Kestrel lol
what
IIS is windows only, for one.
like, you literally can't use it with kubernetes
kestrel isnt some weird fringe software either, its the default asp.net webserver
Yeah I also (after doing some research) I assumed he would be happy to switch, I was also surprised with his reply
Maybe there is some aspect of IIS he knows that I dont, I assumed
Or rather, he is stuck in the past 😄
regardless, in my free time I'll gather up some facts and make a rpesentation to him
Maybe! :D
really? I did not know this
I mean its a windows service
how would it work with a linux based container system?
you also want each container to be self-contained
I dont know, I never tried it but that makes sense yeah
thats why you use kestrel, as it comes with the .net runtime
your gateway/load balancer will "hide" kestrel anyways
so its not going to be exposed to the client
anyways, using HAP, you'd get the time from
vecka.nu
like...
I think the "can't be used with Kubernetes" will be enought to force him to change
and the value is in
weekNumber.InnerHtml
So I would still use HAP for this?
I mean thats what you said no?
I ask because you brought up other technologies
Maybe I expressed incorrectly, I ment to say I have freedom with the parsing
you can use whatever you want. HAP does the trick, but its probably not the fastest.
I would suggest writing some benchmarks if you want to have reliable data on speeds
I can do that actually
wekll first I would have to get the thing running
but after that, i might, it seems like a nice thing to add
After installing a packet with NuGet, I would need to restart the project for it to recognise the types?
wait nvm
figured it out
Thank you for the help so far, it has been incredible the amount of progress I was able to do because of you.
I will go eat now, and then experiment with the new things I learn so far, and read the links posted above
Thank you :)
Well this is weird.
you need to do that before you call
builder.Build();
builder
is being deduced to const?
Oh
Why?what do you think
builder.Build()
does?I see
you can't modify the builder after it has been built, its as simple as that
Its a configuration
yes
Okay, makes sense
Nice how the IDE detects this
It didn't, your application complained 😛
Oh, that was a throw
sorry I just came back from lunch I probably took too much sun in the head ahaha
So I'm reading the following documentation: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis/route-handlers?view=aspnetcore-7.0
In it they mention something called "Route Groups"
But I didn't really understand what they say there
So with this code we give route handlers to each route, and put everything in a Route Group?
And how does that allow me to do things like this?
The
Task<Created<Todos>>
is throwing me off a bitIt's an extension method and the second method is passed as a delegate
Honestly you might aswell make controllers at that point
Why?
RouteGroups is just a way to group a number of handlers under a base route
this is pretty much what controllers do
I see
I probably wont use that tho
Maybe after understanding how many routes I have\
And still I dont think I'll need that
The hardest part for me currently is reading the previous Service code
each .cs file is like 6k lines of code
I think that theoretically there would be a way to copy paste the hole thing, change a few key setup stuff and get it working
that is a lot of code.
im just far from that level yet
Yep, that x10 files
plus some other smaller ones
okay maybe not 6k lines each
avg is like 1.5k lines, I just happened to start with the biggest ones now that I realise
nice aiming lol
Im noticing a pattern
I thought you said these things just forwarded a request and scraped some answers into json?
Well
They to
in theory
Its like this
The things we access dont have a API
so this is like a API for them
we give them functionality we want, and make code that replicates the behaviour
translating the HTML pages into JSON replies
like if we were interacting with a API
still sounds like a lot of code to do that
I know right!
Well
I also notice they do several entities in one file
so like
one big API that covers N websites
the biggest file accesses over 10 websites and over 15 routes for each website
its pretty flexible but the code is huge
Maybe I should start with the smallest one
So that I get a hang of things
the smalles is 450 lines thats pretty manageable
actually I think the website for that smallest one has a API
probably the API doesnt have the functionalities we are looking for tho
So what we do currently is the folowing
Well I still dont fully understand how it works honestly
just part of it
Anyways, this is what is being done
LEts say we want to access some information on website X
website X requires auth
so we make a login request
the class that manages this things keeps track of cookies
so
this is how we get the behaviour of a Session
we can then make more requests to the website
for each request we pass the login credentials
the class checks if there is a session opened for thoes credentials
and uses that session for the request
now I dont know much about this whole web stuff, I'm just learning as I explore the code
Is this a common approach?
Honestly the thing we do is not very common at all, so maybe this is the only approach now that I think about it
Any clues on what the
Procudes
and Route
mean?
Are they required?Sorry I can't read all your messages right now
Route
specifies the route to take to an endpoint. In this case it's on controller level, which makes it the base endpoint for any endpoint in there. So any endpoint has to traverse api/viactt/
, and then additionally their own added route if added. As you can tell, [controller]
indicates the name of the controller, without Controller
prepended to it.
I honestly never used Produces
. I guess it's a hint to indicate what the endpoints return, because modern .NET is smart enough to manually add that header with responses, so it's probably for something like Swagger to understand what the endpoint returns type-wisethey are optional.
I think its for browser. Certain browsers like Firefox have formatter for json, they dont display it like plain text. We show browser that this is json tho
Didn't know that 👍
well its just a guess
i dont "know" it either
xD
Oh 😄
since it defines a MIME-type I just assumed this is what its used for. MIME-types exist to tell browser how to understand data
so according to chat gpt what it does is check if request contains the mime-type in the accept header, if so it will return the response formatted as json with content-type header set to application/json. If client does not contain any supported format in his accept header this will return 406 to any response to indicate that the requested ressource cannot be served in a format that the client can accept
application/json
is a content type header value, and yes, browsers look at that to decide how to display the content. However, the [Produces]
attribute is specifically for stuff like Swagger
you are documenting your API behaviour, which swagger and similar tools can use
Its pretty unusual to "automate" login and handle stateful actions in a website without API access in general, but I dont see much alternatives if thats a requirement.
I hope you have explicit permission from the websites you are doing this to howeverWhat do you mean?
if a website doesnt have an API, that usually means they dont intend for automated usage
so unless you have permission to do this, you most likely violate their TOS
That makes no sense
Why would making my own API to something that doesn't have a API be against TOS? It just changes the way we interact with the functionality they supply
I'm not saying it is, I'm saying it likely is. Its pretty common with TOS statements like "any non-supported automated use is prohibited" or similar.
The idea being if they wanted you to automate their webpage, they would have an API for it
Well, we talk to them regularly, asking them to make APIs, they never get to do it, and the alternative they give us is to make APIs around the website
That counts as explicit permission :p
What can we do
They are so backwards honestly... oh well
this is another topic :)
So
I have a question
Not sure how to ask it
Do you recomend any strategy when dealing with large code bases?
Divide and conquer 🙂
I did some searshing in the code and alot of things the previous maintainer doesnt even know, and others are obsolete
Plus
I made a new thread todday asking about the code structure because Im not used to work with VS, and its a bit weird
I would probably make a class library and write a console app to interface with it, to test it out
and then when the library is "complete" I would integrate it with your web service
But what wold the library do tho?
well, looking at that thread you posted, you already have libraries
each of those
HelperViaCtt
etc projects are class librariesThis is what I have trouble understanding
So from the tutorial I followed
I basically in the
Program.cs
file I made a route
then I gave it a route handler
and that was it
Now in this project
the helper
had a folder called Controllers
, and in it there are basically controllers for every class library
and the code in the controllers is kinda of the code i made form the Program.cs
Lets move this discussion to the other thread?
it seems to be more relevant there
Yes, you are right
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.