{"id":106805,"date":"2022-06-30T07:00:00","date_gmt":"2022-06-30T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=106805"},"modified":"2024-05-17T10:11:00","modified_gmt":"2024-05-17T17:11:00","slug":"20220630-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20220630-00\/?p=106805","title":{"rendered":"How can I build a URL query string in the Windows Runtime?"},"content":{"rendered":"<p>Last time, we looked at <a title=\"How can I parse URL query string in the Windows Runtime?\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20220629-00\/?p=106803\"> a Windows Runtime helper object for parsing URL query strings<\/a>. It also has a helper object for building URL query strings, but for some reason the two aren&#8217;t in the same place.<\/p>\n<p>In C#, you can use a <code>FormUrlEncodedContent<\/code>. In the Windows Runtime, a similar function is provided by the <code>HttpFormUrlEncodedContent<\/code> class. The oddity is that the query parser is in the <code>Windows.<wbr \/>Foundation<\/code> namespace, but the query builder is in the <code>Windows.<wbr \/>Web.<wbr \/>Http<\/code> namespace. My guess is that query parsing is something procotol handlers need to do, whereas query building is something you typically do only when dealing with HTTP servers.<\/p>\n<p>Anyway, here&#8217;s the <code>HttpFormUrlEncodedContent<\/code> class:<\/p>\n<pre>std::map&lt;hstring, hstring&gt; content;\r\ncontent.emplace(L\"v\", L\"dQw4w9WgXcQ\");\r\ncontent.emplace(L\"t\", L\"43s\");\r\nauto encoder = HttpFormUrlEncodedContent(content);\r\nauto encoded = encoder.ToString();\r\n<\/pre>\n<p>You can optimize this by using the <code>initializer_list<\/code> constructor for <code>std::map<\/code>:<\/p>\n<pre>std::map&lt;hstring, hstring&gt; content{\r\n    { L\"v\", L\"dQw4w9WgXcQ\" },\r\n    { L\"t\", L\"43s\" },\r\n};\r\nauto encoder = HttpFormUrlEncodedContent(content);\r\nauto encoded = encoder.ToString();\r\n<\/pre>\n<p>But wait, we can do better: We don&#8217;t need a <code>std::map<\/code> at all. The <code>Http\u00adForm\u00adUrl\u00adEncoded\u00adContent<\/code> constructor takes an <code>IIterator&lt;IKeyValuePair&lt;hstring, hstring&gt;&gt;<\/code>, and C++\/WinRT allows you to pass, among other things, <a href=\"https:\/\/docs.microsoft.com\/en-us\/windows\/uwp\/cpp-and-winrt-apis\/pass-parms-to-abi#map-view-parameters\"> a <code>std::<wbr \/>initializer_<wbr \/>list&lt;std::pair&lt;hstring, hstring&gt;&gt;<\/code><\/a>. Those are easy to make on the fly:<\/p>\n<pre>auto encoder = HttpFormUrlEncodedContent({\r\n    { L\"v\", L\"dQw4w9WgXcQ\" },\r\n    { L\"t\", L\"43s\" },\r\n});\r\nauto encoded = encoder.ToString();\r\n<\/pre>\n<p>And now you can make it a one-liner:<\/p>\n<pre>auto encoded = HttpFormUrlEncodedContent({\r\n    { L\"v\", L\"dQw4w9WgXcQ\" },\r\n    { L\"t\", L\"43s\" },\r\n}).ToString();\r\n<\/pre>\n<p>Note that the <code>Http\u00adForm\u00adUrl\u00adEncoded\u00adContent<\/code> builds a query string. Don&#8217;t use it for encoding the base URL or the fragment. <a title=\"The great thing about URL encodings is that there are so many to choose from\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20100331-00\/?p=14443\"> Those follow different rules<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Pretend you&#8217;re submitting a form.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-106805","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Pretend you&#8217;re submitting a form.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/106805","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=106805"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/106805\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=106805"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=106805"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=106805"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}