开发者

ASP.NET: URI handling

开发者 https://www.devze.com 2022-12-11 11:31 出处:网络
I\'m writing a method which, let\'s say, given 1 and hello should return http://something.com/?something=1&hello=en.

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.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号