Skip to content
This repository was archived by the owner on Dec 20, 2018. It is now read-only.

Conversation

david-peden-q2
Copy link
Contributor

No description provided.

@dnfclas
Copy link

dnfclas commented Nov 4, 2016

Hi @david-peden-q2, I'm your friendly neighborhood .NET Foundation Pull Request Bot (You can call me DNFBOT). Thanks for your contribution!
You've already signed the contribution license agreement. Thanks!
We will now validate the agreement and then real humans will evaluate your PR.

TTYL, DNFBOT;

@david-peden-q2 david-peden-q2 changed the title #55 add rewrite map support to IIS with tests #55 add IIS rewrite map support with tests Nov 4, 2016
Copy link
Contributor

@jkotalik jkotalik left a comment

Choose a reason for hiding this comment

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

Overall looks pretty solid, but there are some general issues we need to verify before we get this in.

{
if (string.IsNullOrEmpty(key))
{
throw new ArgumentException($"{nameof(key)} cannot be empty or null", nameof(key));
Copy link
Contributor

Choose a reason for hiding this comment

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

Sufficient to just throw new ArgException(nameof(key))

{
if (string.IsNullOrEmpty(name))
{
throw new ArgumentException("name cannot be empty or null", nameof(name));
Copy link
Contributor

Choose a reason for hiding this comment

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

Sufficient to just throw new ArgException(nameof(key))

}
if (string.IsNullOrEmpty(value))
{
throw new ArgumentException($"{nameof(value)} cannot be empty or null", nameof(value));
Copy link
Contributor

Choose a reason for hiding this comment

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

See above

private const char CloseBrace = '}';
private readonly IDictionary<string, IISRewriteMap> _rewriteMaps;

public InputParser(IDictionary<string, IISRewriteMap> rewriteMaps = null)
Copy link
Contributor

Choose a reason for hiding this comment

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

Prefer this not to be a default parameter.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

what do you prefer? two constructors? if so, why?

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 it was more of a style thing ASP.NET uses in general

Copy link
Contributor

Choose a reason for hiding this comment

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

so replace with an explicit default constructor and non-null one?

Copy link
Member

Choose a reason for hiding this comment

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

Yes

IISRewriteMap rewriteMap;
if (_rewriteMaps != null && _rewriteMaps.TryGetValue(parameter, out rewriteMap))
{
Pattern pattern = ParseString(context);
Copy link
Contributor

Choose a reason for hiding this comment

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

We use var for all local parameters if possible :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

not great for readability but ok

var rewriteMaps = new Dictionary<string, IISRewriteMap>();
foreach (XElement mapElement in mapsElement.Elements(RewriteTags.RewriteMap))
{
var map = new IISRewriteMap(mapElement.Attribute(RewriteTags.Name)?.Value);
Copy link
Contributor

Choose a reason for hiding this comment

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

Don't think this should be nullable; if the map doesn't have a name, we should probably throw.

{
map.AddOrUpdateEntry(addElement.Attribute(RewriteTags.Key)?.Value, addElement.Attribute(RewriteTags.Value)?.Value);
}
rewriteMaps.Add(map.Name, map);
Copy link
Contributor

Choose a reason for hiding this comment

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

What if we have two rewrite maps of the same name? We should decide whether we throw or overwrite an entry (IMO throwing is better).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Dictionary.Add does throw. are you suggesting we throw an explicit exception?

if (xmlRoot != null)
{
var rewriteMapParser = new RewriteMapParser();
_inputParser = new InputParser(rewriteMapParser.Parse(xmlRoot));
Copy link
Contributor

Choose a reason for hiding this comment

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

👍

{
return value;
}
var exception = new Exception($"Rewrite map entry not found: '{key}'");
Copy link
Contributor

Choose a reason for hiding this comment

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

This style seems a bit odd. I'd refer to how we normally do exception handling with logging errors

{
string key = _pattern.Evaluate(context, ruleMatch, condMatch);
string value;
if (_rewriteMap.TryGetEntry(key, out value))
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 this is wrong. If we don't find an entry in our map, we shouldn't be throwing, it just means it wasn't found in our server variables. Ex I have a url: /foo/bar which maps to foo?bar=1. If our url doesn't equal /foo/bar, it's not an invalid url, it just means it wasn't found in our map.

@davidpeden3 davidpeden3 mentioned this pull request Dec 5, 2016
27 tasks
{
public IDictionary<string, IISRewriteMap> Parse(XElement xmlRoot)
{
var mapsElement = xmlRoot.Descendants(RewriteTags.RewriteMaps).SingleOrDefault();
Copy link
Contributor

Choose a reason for hiding this comment

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

Check here if xmlRoot is null (or nullable)

Copy link
Contributor

Choose a reason for hiding this comment

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

there is already a null check at the call site. should the check be in both places? i'll go ahead and add it but just wanted to point that out.


namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite
{
public class RewriteMapParser
Copy link
Contributor

Choose a reason for hiding this comment

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

You probably want this to be a static helper rather than an object?


if (xmlRoot != null)
{
var rewriteMapParser = new RewriteMapParser();
Copy link
Contributor

Choose a reason for hiding this comment

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

Again can probably make this static.

Name = name;
}

public void AddOrUpdateEntry(string key, string value)
Copy link
Member

Choose a reason for hiding this comment

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

SetEntry?

private const char CloseBrace = '}';
private readonly IDictionary<string, IISRewriteMap> _rewriteMaps;

public InputParser(IDictionary<string, IISRewriteMap> rewriteMaps = null)
Copy link
Member

Choose a reason for hiding this comment

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

Yes


public bool TryGetEntry(string key, out string value)
{
return _map.TryGetValue(key, out value);
Copy link
Member

Choose a reason for hiding this comment

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

It looks like the only caller of this method does _rewriteMap.TryGetEntry(key, out value) ? value : null, so why not build that in and just do a simple GetEntry or an indexer?

@Tratcher Tratcher requested a review from mikaelm12 January 20, 2017 21:09
/// <param name="reader">The text reader stream.</param>
/// <param name="rewriteMaps">An optional set of rewrite maps to uztilize when parsing rules.
/// Rewrite maps in this collection will overwrite (supercede) duplicate named entries in the XML.</param>
public static RewriteOptions AddIISUrlRewrite(this RewriteOptions options, TextReader reader, IEnumerable<IISRewriteMap> rewriteMaps = null)
Copy link
Member

Choose a reason for hiding this comment

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

make a second method rather than using a default parameter

Copy link
Member

Choose a reason for hiding this comment

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

If RewriteMaps are part of the xml file, why pass them in here?

Copy link
Contributor

Choose a reason for hiding this comment

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

For scenarios where there are other sources of rewrite maps. E.g., we have static rules (configured in xml) but have dynamically constructed rewrite maps (from an api/database call). This allows for composing rewrite maps outside of those statically defined in the file.

Copy link
Member

Choose a reason for hiding this comment

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

Is that a supported IIS scenario? We're not trying to add functionality beyond IIS at this point.

Copy link
Contributor

Choose a reason for hiding this comment

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

i don't know but i doubt it. it's a minor addition and something i can account for by purely using the programmatic api. i won't lose sleep over cutting it but it is useful.

Copy link
Member

Choose a reason for hiding this comment

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

cut it for now

Copy link
Contributor

@mikaelm12 mikaelm12 left a comment

Choose a reason for hiding this comment

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

This will also need to be rebased on dev

@@ -0,0 +1,36 @@
using System;
Copy link
Contributor

Choose a reason for hiding this comment

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

Copyright and license header needed here

{
if (xmlRoot == null)
{
throw new ArgumentException(nameof(xmlRoot));
Copy link
Contributor

Choose a reason for hiding this comment

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

Should be an argument null exception

@@ -0,0 +1,22 @@
using Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite;
Copy link
Contributor

Choose a reason for hiding this comment

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

Copyright and license header needed here

using Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite;
using Microsoft.AspNetCore.Rewrite.Internal.PatternSegments;
using Microsoft.Extensions.Logging.Testing;

Copy link
Contributor

Choose a reason for hiding this comment

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

Remove this new line

using System.IO;
using System.Linq;
using System.Xml.Linq;

Copy link
Contributor

Choose a reason for hiding this comment

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

Remove new line

@@ -0,0 +1,43 @@
using System.Collections.Generic;
Copy link
Contributor

Choose a reason for hiding this comment

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

Copyright and license header

var maps = new IISRewriteMapCollection { map };

string inputString = $"{{{expectedMapName}:{{R:1}}}}";
Pattern pattern = new InputParser(maps).ParseInputString(inputString);
Copy link
Contributor

Choose a reason for hiding this comment

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

var

Pattern pattern = new InputParser(maps).ParseInputString(inputString);
Assert.Equal(1, pattern.PatternSegments.Count);

PatternSegment segment = pattern.PatternSegments.Single();
Copy link
Contributor

Choose a reason for hiding this comment

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

var

return;
}
default:
IISRewriteMap rewriteMap = _rewriteMaps?[parameter];
Copy link
Contributor

Choose a reason for hiding this comment

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

var

var mapsElement = xmlRoot.Descendants(RewriteTags.RewriteMaps).SingleOrDefault();
if (mapsElement == null)
{
return null;
Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm. Should we throw here?

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think so. It's valid not to have a rewrite map. Am I missing your point?

Copy link
Contributor

Choose a reason for hiding this comment

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

That's what I was talking about. It just seems like and odd scenario

Copy link
Contributor

Choose a reason for hiding this comment

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

i could move the test for the element outside of the parser and never end up in that scenario but this seems to be the preferred style throughout the project. i definitely don't think it should throw, though. is the structure what's objectionable?

Copy link
Contributor

Choose a reason for hiding this comment

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

No, it should stay here. If its a valid scenario it can stay

}
}


Copy link
Contributor

Choose a reason for hiding this comment

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

nit: Remove this extra new line

@mikaelm12 mikaelm12 merged commit 3faa3de into aspnet:dev Feb 7, 2017
@ondrejsevcik
Copy link

Hi guys, do you have any idea when it get's released?

Thank you 👍

@Tratcher
Copy link
Member

https://github.com/aspnet/Home/wiki/Roadmap Q2 is our next release.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants