I need to define a WCF GET method which can retrieve all the query parameters as a single string. Example:
https://xxx.xxx.xxx.xxx/token?client_id=abc_def&client_name=&type=auth&code=xyz
I want to grab the string "client_id=abc_def&client_name=&type=auth&code=xyz".
How do I define the URI template for the method? I tried the following, but it doesn't work as I will get 400 Bad Request. Replacing the /" with "?" makes no difference.
[WebGet(UriTemplate = "token/{Params}")]
[OperationContract]
Stream GetToken(string Params);
The method will call an external service and just forward whatever query parameters that it receives. I don't want individually retrieve each parameters, as it is possible that the parameters may increase.
Another URL would be like this:
https://xxx.xxx.xxx.xxx/person/123456?client_id=abc_def&client_name=&type=auth&code=xyz
In this case, I would like to grab the two strings "123456" and "client_id=abc_def&client_name=&type=auth&code=xyz".
How do I define the URI template for the method?
You can set the expected query string parameters in UriTemplate, like this:
(UriTemplate = "token/{Params}&client_id={clientId}&client_name={clientName}&type={type}&code={code})
And the method can be declared like this:
Stream GetToken(string Params, string clientId, string clienteName, string type, string code);
You could omit the URI template and use the NameValueCollection from
WebOperationContext.Current.IncomingRequest.UriTemplateMatch.QueryParameters
Then just make a 'ToString()' call and you will get what you want
String fullQueryParams = WebOperationContext.Current.IncomingRequest.UriTemplateMatch.QueryParameters.ToString()
If you need the path as well, for example to retrieve the person and 123456 strings in the url:
https://xxx.xxx.xxx.xxx/person/123456?client_id=abc_def&client_name=&type=auth&code=xyz
you could use WebOperationContext.Current.IncomingRequest.UriTemplateMatch.RelativePathSegments. Then your OperationContract implementation will be something like this:
String fullQueryParams = WebOperationContext.Current.IncomingRequest.UriTemplateMatch.QueryParameters.ToString();
//fullQueryParams = "client_id=abc_def&client_name=&type=auth&code=xyz"
var pathsCollection = WebOperationContext.Current.IncomingRequest.UriTemplateMatch.RelativePathSegments;
//pathsCollection = ["person","12345"]
Related
In AspNet.SignalR.Core, there was this method in IHubConnectionContext where you can send a response to a list of groups while excluding some Connection Ids i.e:
T Groups(IList<string> groupNames, params string[] excludeConnectionIds);
This would be called as:
Clients.Groups(groupNames, exconnectionIds).ReceiveCollaborationNotification(response);
Now I have migrated to AspNetCore.SignalR.Core and there is no such method that accepts both a list of group names and Connection Ids to be excluded. It does have the method mentioned below but this one only accepts one group name, not a list.
T GroupExcept(string groupName, IReadOnlyList<string> excludedConnectionIds);
How can I achieve what T Groups(IList<string> groupNames, params string[] excludeConnectionIds does in AspNetCore.SignalR.Core
In the new SignalR version, you have this extension methods to be invoked:
public static T GroupExcept<T> (this Microsoft.AspNetCore.SignalR.IHubClients<T> hubClients, string groupName, string excludedConnectionId1, string excludedConnectionId2, string excludedConnectionId3, string excludedConnectionId4, string excludedConnectionId5, string excludedConnectionId6, string excludedConnectionId7, string excludedConnectionId8);
You can read more about it here.
So to archive exactly what do you want, you will need to use those extension methods.
I want to have an endpoint that looks like: localhost:5000/abc123
This is basically to replicate the functionality of tinyurl.
Controller
[HttpGet("/{myString}")]
public async Task<IActionResult> Get(string myString)
{}
This works but all files now come through this contoller eg: localhost:5000/runtime.js etc
Is this possible to do only for certain strings?
Use Route constraint to filter values for myString
For example, if a file name is a string containing a dot . is a valid suggestion in your case, you can use the following regex to accept alphanumeric strings
[HttpGet("/{myString::regex(^\\w+$)}")]
I'm currently doing this:
[HttpPut]
public void Edit(int id, Model model)
{
...
}
Which gives me the endpoint /api/controller?id=66 instead of what I want: /api/controller/66
To get what you want -- api/controller/66 on your PUT request, your HTTP verb attribute should be modified to [HttpPut("{id}")]
And the further reason why your id is obtained from the query string by default is that the parameter binding in the case of PUT request works in such a way that the primitive type is bound from request query string and the complex type from request body.
A brief of the parameter binding rules is listed out in this answer.
I want to set up some more complex routes that can include a number of optional parameters. Preferably, I would like to use named parameters for ease of access. Here is an example of what I'm trying to achieve:
// The following routes should be matched based on parameters provided:
// GET /books/:category/:author
// GET /books/:category/:author/limit/:limit
// GET /books/:category/:author/skip/:skip
// GET /books/:category/:author/limit/:limit/skip/:skip
// GET /books/:category/:author/sort/:sortby
// GET /books/:category/:author/sort/:sortby/limit/:limit
// GET /books/:category/:author/sort/:sortby/skip/:skip
// GET /books/:category/:author/sort/:sortby/limit/:limit/skip/:skip
app.get('/books/:category/:author/(sort/:sortby)?/(limit/:limit)?/(skip/:skip)?', myController.index);
As you can see, I'm trying to group the optional parameters with (paramKey/paramValue)?. That way I was hoping to be able to "mix and match" the optional parameters while still making use of the parameter naming. Unfortunately, this doesn't seem to work.
Is there any way to get this working without having to write straight regular expressions and adding additional logic to parse any resulting index-based parameter groups?
Basically, I'm looking for an easy way to parse key/value pairs from the route.
It looks like you want to re-implement the query string using the URL path. My guess is that if you really wanted that, yes, you would have to write your own parsing/interpreting logic. AFAIK express path parameters are positional, whereas the query string is not. Just use a query string and express will parse it for you automatically.
/books?category=sports&author=jack&limit=15?sortby=title
That will enable you to do
req.query.sortby
You may be able to get express to do 1/2 of the parsing for you with a regular expression path like (:key/:value)* or something along those lines (that will match multiple key/value pairs), but express isn't going to then further parse those results for you.
you can send data to view as follow:
//in the server side ...
app.get('/search/:qkey/:qvalue', function(req, res){
res.write(JSON.stringify({
qkey:req.params.qkey;
qvalue:req.params.qvalue;
}));
});
and in the client side... call to ajax
$.ajax({
type:"POST",
url:"/search/"+qkey+"/"+qvalue,
success: function(data){
var string = eval("(" + data + ")");
//you access to server response with
console.log(string.qkey+" and "+ string.qvalue);
}
});
I'm developing some RESTful services in WCF 4.0. I've got a method as below:
[OperationContract]
[WebGet(UriTemplate = "Test?format=XML&records={records}", ResponseFormat=WebMessageFormat.Xml)]
public string TestXml(string records)
{
return "Hello XML";
}
So if i navigate my browser to http://localhost:8000/Service/Test?format=XML&records=10, then everything works as exepcted.
HOWEVER, i want to be able to navigate to http://localhost:8000/Service/Test?format=XML and leave off the "&records=10" portion of the URL. But now, I get a service error since the URI doesn't match the expected URI template.
So how do I implement defaults for some of my query string parameters? I want to default the "records" to 10 for instance if that part is left off the query string.
Note: This question is out of date, please see the other answers.
This does not appear to be supported.
However, Microsoft has been made aware of this issue and there is a work-around:
You can get the desired effect by
omitting the Query string from the
UriTemplate on your WebGet or
WebInvoke attribute, and using
WebOperationContext.Current.IncomingRequest.UriTemplateMatch.QueryParameters
from within your handlers to inspect,
set defaults, etc. on the query
parameters.
https://connect.microsoft.com/VisualStudio/feedback/details/451296/
According to this answer this is fixed in .NET 4.0. Failing to supply the query string parameter seems to result in its being given the default value for the type.
Check this blog post out. Makes sense to me, and comes with a class to parse out the query string parameters.
http://blogs.msdn.com/b/rjacobs/archive/2009/02/10/ambiguous-uritemplates-query-parameters-and-integration-testing.aspx
Basically don't define the query string parameters in the UriTemplate so it matches with/without the parameters, and use the sample class to retrieve them if they're there in the method implementation.
This seems to work in WCF 4.0.
Just make sure to set your default value in your "Service1.svc.cs"
public string TestXml(string records)
{
if (records == null)
records = "10";
//... rest of the code
}
While this is an old question, we still come to this scenario from time to time in recent projects.
To send optional query parameters, I created WCF Web Extensions nuget package.
After installation, you can use the package like this:
using (var factory = new WebChannelFactory<IQueryParametersTestService>(new WebHttpBinding()))
{
factory.Endpoint.Address = new EndpointAddress(ServiceUri);
factory.Endpoint.EndpointBehaviors.Add(new QueryParametersServiceBehavior());
using (var client = factory.CreateWebChannel())
{
client.AddQueryParameter("format", "xml");
client.AddQueryParameter("version", "2");
var result = client.Channel.GetReport();
}
}
Server side you can retrieve the parameters using WebOperationContext:
WebOperationContext.Current.IncomingRequest.UriTemplateMatch.QueryParameters;