【问题标题】:Alternative to .NET's Uri implementation?.NET 的 Uri 实现的替代方案?
【发布时间】:2009-02-10 11:22:39
【问题描述】:

我对 .NET 的 Uri 实现有疑问。似乎如果方案是“ftp”,则查询部分不会被解析为查询,而是作为路径的一部分。

以如下代码为例:

Uri testuri = new Uri("ftp://user:pass@localhost/?passive=true");
Console.WriteLine(testuri.Query); // Outputs an empty string
Console.WriteLine(testuri.AbsolutePath); // Outputs "/%3Fpassive=true"

在我看来,Uri 类错误地将查询部分解析为路径的一部分。不过将scheme改成http,结果如预期:

Uri testuri = new Uri("http://user:pass@localhost/?passive=true");
Console.WriteLine(testuri.Query); // Outputs "?passive=true"
Console.WriteLine(testuri.AbsolutePath); // Outputs "/"

有没有人对此有解决方案,或者知道可以按预期工作的替代 Uri 类?

【问题讨论】:

    标签: c# .net ftp uri


    【解决方案1】:

    好吧,问题不在于我无法创建 FTP 连接,而是 URI 未根据 RFC 2396 进行解析。

    我实际上打算创建一个工厂,它基于给定的连接 URI 提供通用文件传输接口(包含 get 和 put 方法)的实现。 URI 定义了协议、用户信息、主机和路径,任何需要传递的属性都应该通过 URI 的 Query 部分(例如 FTP 连接的 Passive 模式选项)。

    然而,使用 .NET Uri 实现证明这很困难,因为它似乎根据架构以不同的方式解析 URI 的查询部分。

    所以我希望有人知道解决此问题的方法,或替代看似损坏的 .NET Uri 实现的替代方法。在花几个小时实施我自己的之前知道会很高兴。

    【讨论】:

    • 为什么不检查 URI 是否以 ftp: 开头,然后将方案更改为 x.generic: 之类的?你会从中得到查询。
    【解决方案2】:

    我已经为同样的问题苦苦挣扎了一段时间。尝试使用 UriParser.Register 为“ftp”方案替换现有的 UriParser 会引发 InvalidOperationException,因为该方案已注册。

    我提出的解决方案涉及使用反射来修改现有的 ftp 解析器,以便它允许查询字符串。这是基于another UriParser bug 的解决方法。

    MethodInfo getSyntax = typeof(UriParser).GetMethod("GetSyntax", System.Reflection.BindingFlags.Static
                                                                  | System.Reflection.BindingFlags.NonPublic);
    FieldInfo flagsField = typeof(UriParser).GetField("m_Flags", System.Reflection.BindingFlags.Instance
                                                               | System.Reflection.BindingFlags.NonPublic);
    if (getSyntax != null && flagsField != null)
    {
        UriParser parser = (UriParser)getSyntax.Invoke(null, new object[] { "ftp"});
        if (parser != null)
        {
            int flagsValue = (int)flagsField.GetValue(parser);
    
            // Set the MayHaveQuery attribute
            int MayHaveQuery = 0x20;
            if ((flagsValue & MayHaveQuery) == 0) flagsField.SetValue(parser, flagsValue | MayHaveQuery);
        }
    }
    

    在初始化的某个地方运行它,您的 ftp Uris 将使查询字符串进入 Query 参数,正如您所期望的那样,而不是 Path

    【讨论】:

      【解决方案3】:

      您应该使用FtpWebRequestFtpWebResponse 类,除非您有特定的理由不这样做。

      FtpWebRequest.fwr = (FtpWebRequest)FtpWebRequest.Create(new Uri("ftp://uri"));
      fwr.ftpRequest.Method = WebRequestMethods.Ftp.UploadFile;
      fwr.ftpRequest.Credentials = new NetworkCredential("user", "pass");
      
      
      FileInfo ff = new FileInfo("localpath");
      byte[] fileContents = new byte[ff.Length];
      
      using (FileStream fr = ff.OpenRead())
      {
         fr.Read(fileContents, 0, Convert.ToInt32(ff.Length));
      }
      
      using (Stream writer = fwr.GetRequestStream())
      {
         writer.Write(fileContents, 0, fileContents.Length);
      }
      
      FtpWebResponse frp = (FtpWebResponse)fwr.GetResponse();
      Response.Write(frp.ftpResponse.StatusDescription); 
      

      Ref1Ref2

      【讨论】:

        【解决方案4】:

        您必须为 FTP 协议使用特定的类,例如 FtpWebRequest,它具有像 RequestUri 这样的 Uri 属性。

        您应该在这些类中搜索我认为的 Uri 解析器。

        【讨论】:

          最近更新 更多