ASP.NET: URI handling
I'm writing a method which, let's say, given 1 and hello should return http://something.com/?something=1&hello=en.
I could hack this together pretty easily, but what abstraction functionality does ASP.NET 3.5 provide for building URIs? I'd like something like:
URI uri = new URI("~/Hello.aspx"); // E.g. ResolveUrl is used here
uri.QueryString.Set("something", "1");
uri.QueryString.Set("hello", "en");
return uri.ToString(); // /Hello.aspx?something=1&hello=en
I found the Uri 开发者_运维技巧class which sounds highly relevant, but I can't find anything which does the above really. Any ideas?
(For what it's worth, the order of the parameters doesn't matter to me.)
Edited to correct massively incorrect code
Based on this answer to a similar question you could easily do something like:
UriBuilder ub = new UriBuilder();
// You might want to take more care here, and set the host, scheme and port too
ub.Path = ResolveUrl("~/hello.aspx"); // Assumes we're on a page or control.
// Using var gets around internal nature of HttpValueCollection
var coll = HttpUtility.ParseQueryString(string.Empty);
coll["something"] = "1";
coll["hello"] = "en";
ub.Query = coll.ToString();
return ub.ToString();
// This returned the following on the VS development server:
// http://localhost/Hello.aspx?something=1&hello=en
This will also urlencode the collection, so:
coll["Something"] = "1";
coll["hello"] = "en&that";
Will output:
Something=1&hello=en%26that 
As far I know nothing here. So everybody has its own implementation.
Example from LinqToTwitter.
    internal static string BuildQueryString(IEnumerable<KeyValuePair<string, string>> parameters)
    {
        if (parameters == null)
        {
            throw new ArgumentNullException("parameters");
        }
        StringBuilder builder = new StringBuilder();
        foreach (var pair in parameters.Where(p => !string.IsNullOrEmpty(p.Value)))
        {
            if (builder.Length > 0)
            {
                builder.Append("&");
            }
            builder.Append(Uri.EscapeDataString(pair.Key));
            builder.Append("=");
            builder.Append(Uri.EscapeDataString(pair.Value));
        }
        return builder.ToString();
    }
UPDATE:
You can also create extension method:
public static UriBuilder AddArgument(this UriBuilder builder, string key, string value)
{
 #region Contract
 Contract.Requires(builder != null);
 Contract.Requires(key != null);
 Contract.Requires(value != null);
 #endregion
 var query = builder.Query;
 if (query.Length > 0)
 {
      query = query.Substring(1) + "&";
 } 
 query += Uri.EscapeDataString(key) + "="
      + Uri.EscapeDataString(value);
 builder.Query = query;
 return builder;
}
And usage:
var b = new UriBuilder();
b.AddArgument("test", "test");
Please note that everything here is untested.
Just combined answers=>
public static class UriBuilderExtensions
{
    public static void AddQueryArgument(this UriBuilder b, string key, string value)
    {
        key = Uri.EscapeDataString(key);
        value = Uri.EscapeDataString(value);
        var x = HttpUtility.ParseQueryString(b.Query);
        if (x.AllKeys.Contains(key)) throw new ArgumentNullException
                ("Key '{0}' already exists!".FormatWith(key));
        x.Add(key, value);
        b.Query = x.ToString();
    }
    public static void EditQueryArgument(this UriBuilder b, string key, string value)
    {
        key = Uri.EscapeDataString(key);
        value = Uri.EscapeDataString(value);
        var x = HttpUtility.ParseQueryString(b.Query);
        if (x.AllKeys.Contains(key))
            x[key] = value;
        else throw new ArgumentNullException
                ("Key '{0}' does not exists!".FormatWith(key));
        b.Query = x.ToString();
    }
    public static void AddOrEditQueryArgument(this UriBuilder b, string key, string value)
    {
        key = Uri.EscapeDataString(key);
        value = Uri.EscapeDataString(value);
        var x = HttpUtility.ParseQueryString(b.Query);
        if (x.AllKeys.Contains(key))
            x[key] = value;
        else
            x.Add(key, value);
        b.Query = x.ToString();
    }
    public static void DeleteQueryArgument(this UriBuilder b, string key)
    {
        key = Uri.EscapeDataString(key);
        var x = HttpUtility.ParseQueryString(b.Query);
        if (x.AllKeys.Contains(key))
            x.Remove(key);
        b.Query = x.ToString();
    }
}
Half baked code. But should work well enough.
There's also the UriBuilder class
This is something that might appeal to you- recently at work I was looking at a way to "type" commonly used URL query string variables and so developed this interface:
   'Represent a named parameter that is passed from page-to-page via a range of methods- query strings, HTTP contexts, cookies, session, etc.
Public Interface INamedParam
    'A key that uniquely identfies this parameter in any HTTP value collection (query string, context, session, etc.)
    ReadOnly Property Key() As String
    'The default value of the paramter.
    ReadOnly Property DefaultValue() As Object
End Interface
You can then implement this interface to describe a query string parameter, such an implementation for your "Hello" param might look like this:
Public Class HelloParam
    Implements INamedParam
    Public ReadOnly Property DefaultValue() As Object Implements INamedParam.DefaultValue
        Get
            Return "0"
        End Get
    End Property
    Public ReadOnly Property Key() As String Implements INamedParam.Key
        Get
            Return "hello"
        End Get
    End Property
End Class
I developed a small (and very, very basic) class to help build URLs using these strongly typed parameters:
Public Class ParametrizedHttpUrlBuilder
    Private _RelativePath As String
    Private _QueryString As String
    Sub New(ByVal relativePath As String)
        _RelativePath = relativePath
        _QueryString = ""
    End Sub
    Public Sub AddQueryParameterValue(ByVal param As INamedParam, ByVal value As Object)
        Dim sb As New Text.StringBuilder(30)
        If _QueryString.Length > 0 Then
            sb.Append("&")
        End If
        sb.AppendFormat("{0}={1}", param.Key, value.ToString())
        _QueryString &= sb.ToString()
    End Sub
    Public Property RelativePath() As String
        Get
            Return _RelativePath
        End Get
        Set(ByVal value As String)
            If value Is Nothing Then
                _RelativePath = ""
            End If
            _RelativePath = value
        End Set
    End Property
    Public ReadOnly Property Query() As String
        Get
            Return _QueryString
        End Get
    End Property
    Public ReadOnly Property PathAndQuery() As String
        Get
            Return _RelativePath & "?" & _QueryString
        End Get
    End Property
End Class
Here's my version (needs .NET4 or a ToArray() call on the Select)
var items = new Dictionary<string,string> { { "Name", "Will" }, { "Age", "99" }};
String query = String.Join("&", items.Select(i => String.Concat(i.Key, "=", i.Value)));
I thought the use of Dictionary might mean the items can get reordered, but that doesn't actually seem to be happening in experiments here - not sure what that's about.
 
         加载中,请稍侯......
 加载中,请稍侯......
      
精彩评论