This might seem dirty but it's for documentation purposes I swear!
I am accessing my services using GETs in my documentation so people can try things out without needing to get too complicated.
Appending x-http-method-override=POST to the URL forces the server to take a GET as a POST
This is all good except when I need to POST an array of objects. This would be simple in a standard POST but today I have a new bread of nightmare.
The expected POST looks like:
{"name":"String","slug":"String","start":"String","end":"String","id":"String","artists":[{"id":"String","name":"String","slug":"String"}],"locationId":"String"}
As you can see there is an array of artists up in here.
I have tried to do the following:
model/listing?start=10:10&end=12:30&artists[0].name=wayne&artists[0].id=artists-289&locationid=locations-641&x-http-method-override=POST
But to no avail.
How can I get an array of objects into a URL so that service stack will be happy with it?!
I appreciate this is not the done thing but it's making explaining my end points infinitely easier with clickable example URLs
You can use JSV to encode complex objects in the URL. This should work for your DTO:
model/listing?name=wayne&artists=[{id:artists-289,name:sample1},{id:artists-290,name:sample2}]&locationId=locations-641
You can programmatically create JSV from an arbitrary object using the ToJsv extension method in ServiceStack.Text.
Related
Maybe this isn't even possible, but it seems silly that I can't figure it out (nor can find anything conclusive after searching).
With a MVC/C# Web API 2 project, your controllers can be documented using something like:
///<summary>
///This is something really cool that you should use. I want <b>this bold</b>.
///</summary>
[HttpPost]
public MyResponse MyMethod(SomeInput input)
{
....
}
When the API runs, the project automatically builds the help site, and I can see the above endpoint/method, and its description ( text), but I've head to figure out how to do any sort of styling to the summary. It appears that the HTML tags get striped from the help page's output. Notice in my example above, I have "this bold". I'm not so much concerned about bold, but more interested in being able to use unordered lists () and other basic HTML tags to just do some real basic formatting.
Is this even possible?
Is there a trick to it?
Is there some other markup/formatting I should be using?
Note - The actual endpoint that I'm trying to document at moment, happens to be a mime multipart form, and the framework won't document those out of the box. To get around this, I've created some helper methods in HelpPageConfigurationExtensions (to determine if the current endpoint view is one that requires custom documentation), in HelpPageApiModel.cshtml to determine if it should show the stock documentation or the custom docs, a helper library that contains the custom doc information, and a series of help functions that use some reflection to rapidly build HTML tables for the rest of the help page's documentation (e.g. the request and response objs). I'm mentioning this because maybe I just need to further extend my custom doc library to include (hard code) the value, and then in the view I can just #Html.Raw it -- opposed to trying to get the actual method's to output with formatting.
Thoughts?
Thanks!
I'm looking to use Swashbuckle to generate Swagger docs and Swagger UI for a Web API method that looks like the following (it's effectively a mail-merge with PDFs):
[HttpPost]
[ResponseType(typeof(byte[]))]
public HttpResponseMessage MergeValues([FromUri]Dictionary<string, string> mergeValues,
[FromBody]byte[] pdfTemplate)
{
return MergeStuff();
}
This isn't currently working, or at least I'm not sure how to interact with the resulting Swagger UI.
This creates the following Swagger UI, which seems reasonable, but I'm not sure what to do with it to populate it correctly (or if it's even correct). I'm using pretty much all default Swashbuckle settings from the latest Nuget.
Byte Array: If I enter Base64-encoded text for the byte array, the byte array always shows up null. Turns out I just need my BASE64 text surrounded by double-quotes and then it works.
Dictionary: I've tried various types of JSON expressions (arrays, objects, etc) and am unable to get any of the values in the Dictionary to populate (the resulting Dictionary object has 0 items).
I have the ability to change things and would like to know how I can do this. For example, if changing the dictionary to an array of KeyValuePair<string,string> helps, let's do it.
Options I know that I have that I'd like to avoid:
Changing these input types to strings and doing my own manual deserialization/decoding. I'd like to be explicit with my types and not get too fancy.
Custom binders. I'd like to utilize standard/default binders so I have less code/complexity to maintain.
My question really was a two-parter. Here are the answers, although only a partial answer to the second question:
Question 1: How do I fill in the data for a byte array?
Answer 1: Paste in your base64-encoded value for it but be sure to surround that content with double-quotes, both at the beginning and end.
Question 2: How do I fill in the data for the Dictionary?
Answer 2: While it doesn't work with [FromUri], this will work with [FromBody] (either Dictionary or IDictionary<string,string> will work):
{"FirstName":"John","LastName":"Doe"}
I'm not sure why this doesn't work with FromUri but I'm going to ask a separate question that's much more focused than this one to get to the bottom of that. For the purposes of this question, both parameters can be put into a DTO, flagged as [FromBody], and all is good then.
Unfortunately because of the wide use of the word "hashtag" and "httprequest" i couldn't find any search results that gave me an answer on whether something like this is even possible.
If i have a url like this:
/Orders/Product#12345
The HttpRequest class shows me that the FilePath, RawUrl, and all other members that show the url as
/Orders/Product
It just gets rid of the hashtag, and i can't find a place to view it.
Is there any way for me to be able to see what hashtag is at the end of the URL from the codebehind? I know i could easily make this a QueryString parameter, but i like the way this looks better, so if there's a way to do it, i'd like to find out what it is :)
Thanks in advance!
It just gets rid of the hashtag, and i can't find a place to view it.
That's because it doesn't get sent to the server. It's not part of the request - it's only relevant on the client side. If you need to do anything clever with it, you'll need to write some Javascript to access it.
Browser is not required to do GET request in case of navigation to bookmarks on the same page (what #12345 is). So you may reconsider using it for normal requests.
As others have stated this value is not sent to the server. While it's possible to send the value to the server using JavaScript, in this instance you should make it a query string parameter.
If you are using it in a view:
Typeahead
There are some posts on this, but not an answer to this specific question.
The server is returning this: "/Date(1304146800000)/"
I would like to not change the server-side code at all and instead parse the date that is included in the .Net generated JSON object. This doesn't seem that hard because it looks like it is almost there. Yet there doesn't seem to be a quick fix, at least in these forums.
From previous posts it sounds like this can be done using REGEX but REGEX and I are old enemies that coldly stare at each other across the bar.
Is this the only way? If so, can someone point me to a REGEX reference that is appropriate to this task?
Regards,
Guido
The link from Robert is good, but we should strive to answer the question here, not to just post links.
Here's a quick function that does what you need. http://jsfiddle.net/Aaa6r/
function deserializeDotNetDate(dateStr) {
var matches = /\/Date\((\d*)\)\//.exec(dateStr);
if(!matches) {
return null;
}
return new Date( parseInt( matches[1] ) );
}
deserializeDotNetDate("/Date(1304146800000)/");
Since you're using jQuery I've extended its $.parseJSON() functionality so it's able to do this conversion for you automatically and transparently.
It doesn't convert only .net dates but ISO dates as well. ISO dates are supported by native JSON converters in all major browsers but they work only one way because JSON spec doesn't support date data type.
Read all the details (don't want to copy blog post content here because it would be too much) in my blog post and get the code as well. The idea is still the same: change jQuery's default $.parseJSON() behaviour so it can detect .Net and ISO dates and converts them automatically when parsing JSON data. This way you don't have to traverse your parsed objects and convert dates manually.
How it's used?
$.parseJSON(yourJSONstring, true);
See the additional variable? This makes sure that all your existing code works as expected without any change. But if you do provide the additional parameter and set it to true it will detect dates and convert them accordingly.
Why is this solution better than manual conversion? (suggested by Juan)
Because you lower the risk of human factor of forgetting to convert some variable in your object tree (objects can be deep and wide)
Because your code is in development and if you change some server-side part that returns JSON to the client (rename variables, add new ones, remove existing etc.), you have to think of these manual conversions on the client side as well. If you do it automatically you don't have to think (or do anything) about it.
Two top reasons from the top of my head.
When overriding jQuery functionality feels wrong
When you don't want to actually override existing $.parseJSON() functionality you can minimally change the code and rename the extension to $.parseJSONwithdates() and then always use your own function when parsing JSON. But you may have a problem when you set your Ajax calls to dataType: "json" which automatically calls the original parser. If you use this setting you will have to override jQuery's existing functionality.
The good thing is also that you don't change the original jQuery library code file. You put this extension in a separate file and use it at your own will. Some pages may use it, others may not. But it's wise to use it everywhere otherwise you have the same problem of human factor with forgetting to include the extension. Just include your extension in some global Javascript file (or master page/template) you may be using.
In my web application I include all of my JavaScripts as js files that are embedded resources in the assembly, and add them to the page using ClientScriptManager.GetWebResourceUrl(). However, in some of my js files, I have references to other static assets like image urls. I would like to make those assembly resources as well. Is there a way to tokenize the reference to the resource? e.g.
this.drophint = document.createElement('img');
this.drophint.src = '/_layouts/images/dragdrophint.gif';
Could become something like:
this.drophint = document.createElement('img');
this.drophint.src = '{resource:assembly.location.dragdrophint.gif}';
I'd suggest that you emit the web resources as a dynamic javascript associative array.
Server side code:
StringBuilder script = new StringBuilder();
script.Append("var imgResources = {};");
script.AppendFormat("imgResources['{0}'] = '{1}';",
"drophint",
Page.ClientScript.GetWebResourceUrl(Page.GetType(), "assembly.location.dragdrophint.gif"));
script.AppendFormat("imgResources['{0}'] = '{1}';",
"anotherimg",
Page.ClientScript.GetWebResourceUrl(Page.GetType(), "assembly.location.anotherimg.gif"));
Page.ClientScript.RegisterClientScriptBlock(
Page.GetType(),
"imgResources",
script.ToString(),
true);
Then your client side code looks like this:
this.drophint = document.createElement('img');
this.drophint.src = imgResources['drophint'];
this.anotherimg = document.createElement('img');
this.anotherimg.src = imgResources['anotherimg'];
Hope this helps.
I don't particularly care for the exact implementation #Jon suggests, but the idea behind it is sound and I would concur that emitting these would be a good thing to do.
A slightly better implementation, though this is all subjective to some degree, would be to create a server-side model (read: C# class(es)) that represents this dictionary (or simply use an instance of Dictionary<string, string>) and serialize that to JavaScript literal object notation. That way you are not dealing with the string hacking you see in Jon's example (if that bothers you).
I concur with Jason's assessment of the initial solution I proposed, it can definitely be improved. My solution represents an older school javascript mentality (read, pre the emergence of ajax and JSON). There are always better ways to solve a problem, which one of the reasons why StackOverflow is so cool. Collectively we are better at the craft of programming than anyone of us on our own.
Based on Jason's ideas I'd revise my initial code, and revise some of what Jason suggested. Implement a C# class with two properties, the img resource id and a property that contains the WebResourceUrl. Then, where I differ some from Jason is that rather than using a Dictionary<string, string> I'd propose using a List<MyImageResourceClass>, which you can then in turn serialize to JSON (using DataContractJsonSerializer), and emit the JSON as the dynamic script, rather than manually generating the javascript using a string builder.
Why a List? I think you may find that dictionaries when serialized to JSON, at least using the DataContractJsonSerializer (fyi available with the 3.5 framework only, with the 2.0 or 3.0 framework you'd need to bolt on aspnet ajax and use is JSON serializer), are a little more cumbersome to work with than how a list would serialize. Although that is subjective.
There are implications too with your client side code. Now on the client side you'll have an array of the JSON serialized MyImageResourceClass instances. You'd need to iterate through this array creating your img tags as you go.
Hopefully, these ideas and suggestions can help get you going! And no doubt there are other solutions. I'm interested to see what comes of this.