Skip to content

Conversation

brandonh-msft
Copy link
Contributor

The purpose of this PR is to provide UWP devs an easy way to deal with Deep link URIs as they become more and more a part of the services we create for devs to consume. Bot Framework, Cortana launches, etc all rely on deep links in to apps to ultimately provide value.

DeepLinkParser

This class provides a way to create, from IActivatedEventArgs a Dictionary<string,string>-inheriting object that provides an additional .Root property to pull the base path of the URI (eg: in MainPage/Options?option1=value1, .Root would be MainPage/Options.
Once you have an instance, simply saying instance["optionName"] will pull the value from the querystring for that option.

CollectionFormingDeepLinkParser

Some consumers want to be able to do something like ?pref=this&pref=that&pref=theOther and have a pull of pref come back with this,that,theOther as its value. This derivative of DeepLinkParser provides this functionality.

Both of these are createable using a .Create(IActivatedEventArgs) method. Should a user wish to create one in a different manner, the default constructor is protected so inheriting from either of these can provide extensibility should they wish to pass in just a string, etc. The method that does the heavy lifting of parsing in to the Dictionary<string,string> is also protected so can be used by any inheriting class.

@msftclas
Copy link

Hi @brandonh-msft, I'm your friendly neighborhood Microsoft Pull Request Bot (You can call me MSBOT). Thanks for your contribution!


It looks like you're a Microsoft contributor (Brandon Hurlburt). If you're full-time, we DON'T require a Contribution License Agreement. If you are a vendor, please DO sign the electronic Contribution License Agreement. It will take 2 minutes and there's no faxing! https://cla.microsoft.com.

TTYL, MSBOT;

.Select(param =>
{
var kvp = param.Split('=');
return new KeyValuePair<string, string>(kvp[0], kvp[1]);
Copy link
Contributor

@ScottIsAFool ScottIsAFool Sep 22, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You've essentially done this conversion to KeyValuePair list twice now, could we move this to a helper method instead?

var origString = validatedUri.OriginalString;
int queryStartPosition = origString.IndexOf('?');
if (queryStartPosition == -1)
{ // No querystring on the URI
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think style suggests that comments should be on the next line.

int queryStartPosition = origString.IndexOf('?');
if (queryStartPosition == -1)
{ // No querystring on the URI
this.Root = origString;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove usages of this.

@deltakosh deltakosh added this to the v1.2 milestone Sep 26, 2016
@deltakosh
Copy link
Contributor

up

@brandonh-msft
Copy link
Contributor Author

@deltakosh i submitted a new push, should be able to merge it in no problem.

@IbraheemOsama
Copy link
Member

@brandonh-msft it seems like there are conflicts that must be resolved.

{
public TestContext TestContext { get; set; }

private const string SAMPLELINK = @"MainPage/Options?option1=value1&option2=value2&option3=value3";
Copy link
Member

@IbraheemOsama IbraheemOsama Oct 6, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this should be SampleLink not SAMPLELINK

public TestContext TestContext { get; set; }

private const string SAMPLELINK = @"MainPage/Options?option1=value1&option2=value2&option3=value3";
private static readonly DeepLinkParser _parser = new TestDeepLinkParser(SAMPLELINK);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also _parser should be Parser

public class CollectionCapableDeepLinkParserTests
#pragma warning restore SA1402 // File may only contain a single class
{
private const string SAMPLELINK = @"MainPage/Options?option1=value1&option2=value2&option3=value3&option2=value4";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SAMPLELINK Should be SampleLink too

#pragma warning restore SA1402 // File may only contain a single class
{
private const string SAMPLELINK = @"MainPage/Options?option1=value1&option2=value2&option3=value3&option2=value4";
private static readonly DeepLinkParser _parser = new TestCollectionCapableDeepLinkParser(SAMPLELINK);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_parser should be Parser

@lukasf
Copy link
Contributor

lukasf commented Oct 24, 2016

Is there a specific reason why you do not open this up for use with normal string or uri arguments? Parsing options from uri strings is a very common scenario, not only useful for deeplinks but also all other kinds of links.

Even when only using this for deep links, it should be opened up for string arguments as well: I am pretty sure that in almost all apps, the string will be passed to a frame's navigate function. So in the app class, only the .Root will be checked to get the page type. Only later in the page's navigate function, the user will actually want to parse out the parameters from the string argument. So a DeepLinkParser which only works with IActivatedEventArgs would be pretty useless for most apps, I think. I would propose to at least give it a public string overload. And if you ask me, I'd even rename it to something like LinkParser or LinkQueryParser and add an Uri overload as well, to make it truly universal.

@brandonh-msft
Copy link
Contributor Author

@lukasf
Deep links launch in to the Activated method, which has the deep link as part of the IActivatedEventArgs parameter.
Note that the construct is not sealed. Creating one that takes a string would be trivial should someone deem that necessary in their project.

@deltakosh
Copy link
Contributor

Do you mind fixing conflicts and checking @IbraheemOsama ask?

@brandonh-msft
Copy link
Contributor Author

@deltakosh
since @IbraheemOsama's asks were all stylistic, are there some more/other analyzers we can apply/enforce here?

@brandonh-msft
Copy link
Contributor Author

@lukasf you might want to check out a branch i already had in my fork but haven't yet updated to the latest code if you're interested in this approach.
Forgot i'd played w/ just such a solution as a way to feel out the extensibility :)

@lukasf
Copy link
Contributor

lukasf commented Oct 24, 2016

@brandonh-msft My point is, the vast majority of apps use frame navigation, they will need to have the link options accessible in the page's OnNavigatedTo() function. It does not help much to have the link options available in the App class, when there is no way to pass complex objects (such as the DeepLinkParser, Dictionaries, etc) through there without breaking Frame's navigation state serialization. So the easiest way for all these apps to work with deep links is to pass the deep link as string parameter to Frame.Navigate() and then parse out the options in Page.OnNavigatedTo(). The goal of this toolkit is to simplify things for developers. It would be very unfortunate if nearly all app devs would need to inherit DeepLinkParser, only to successfully use it with frame navigation apps.

@brandonh-msft
Copy link
Contributor Author

@lukasf
I understand what you're saying. Links passed to pages aren't "deep links" - they're parameter values. The app-level Activated method still needs to hit that content then kick it off to the page. At which point the Activated method could send them the URI string that came in (from which DeepLinkParser was created) or the raw string, or a few values that were pulled out by the parser. I wouldn't expect a parser to be sent to a page. I'd expect a value to.

Regardless, i'll work on shoring up the string-capable version of this PR and add it in.

@lukasf
Copy link
Contributor

lukasf commented Oct 25, 2016

@brandonh-msft Normally I would fully agree with you. But unfortunately there is this restriction that the parameter passed to the Page through Frame.Navigate can only be one of the simple types string, numeric, char or Guid. No complex values are allowed, no dicts or arrays. So passing data as a single string is the only feasible way. If there is no string overload in DeepLinkParser, devs would have to serialize the parsed options again in the app and then deserialize in the page. With string overload, they can just move the options parsing right into the page and save the whole serialize/deserialize. I am sure that this will be very useful to a lot of devs.

@ScottIsAFool
Copy link
Contributor

Eh? That's simply not true. Frame.Navigate can have anything passed through, I do it all the time.

@lukasf
Copy link
Contributor

lukasf commented Oct 25, 2016

@ScottIsAFool Well right, you can pass anything, but then the next call to GetNavigationState() will fail with an exception. If you want to persist the frame naviagation state on app suspend/resume, you cannot pass complex values. This is also mentioned in the msdn docs for Frame.Navigate().

@ScottIsAFool
Copy link
Contributor

@lukasf right, you made no comment about this originally, hence the confusion :) thanks for clarifying.

@lukasf
Copy link
Contributor

lukasf commented Oct 25, 2016

@ScottIsAFool Sure, no worries. :) Sorry for the confusion.

@brandonh-msft
Copy link
Contributor Author

@lukasf
Please note that the code includes string overloads as of yesterday. need to figure out why build works on my box but fails in appveyor now.

@deltakosh
Copy link
Contributor

Conflicts :( Sorry should be because of last merges)

nice exception for repeated keys when using DeepLinkParser

more meaningful var name

more single-char var name fixes

xml doco fix

Uri & string overloads along with UTs
…ng of query parameters from a string or Uri in to a collection that can be iterated on
adding StyleCop analyzers to UT project

Stylecop ignoring as did review call stack.
@deltakosh
Copy link
Contributor

Just discussed with @brandonh-msft regarding doc
A new PR will be submitted for it

@brandonh-msft brandonh-msft deleted the Deep-link-parsers branch October 27, 2016 16:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants