简体   繁体   中英

WPF or WinForms, MVC querystring-like value provider/binding

I'm working on a WPF project using a third party web browser control. To pass data from the web page I'm doing a redirect in JavaScript and then cancelling the "Navigating" event of the browser [see Using WebKit.NET to call a C# function from JavaScript).

In the navigating event I'm doing some URL crunching to create a dictionary of arguments from the URL parameters, and then call a particular method (also based on the URL).

With a URL that looks something like this = 'app-Method?arg1=5.3&arg2=3' I end up with a Dictionary containing the following information:

//var methodName = "Method";
//var dictionary = { { "arg1", "5.3" }, { "arg2", "3" } };

It I can't do the conversion at this stage as different methods would have different arguments with different types.

I'd then call another method (method name from the URL) like this:

switch(methodName)
{
     case "Method":
         Method(Convert.ToDecimal(dictionary["arg1"]), Convert.ToInt(dictionary["arg2"]));
         break;
}

Obviously in MVC a HTTPGet action method does all this conversion, crunching, and method calling for me. I was wondering if (using the MVC libraries or some other method) it is possible to replicate this sort of behaviour in a non-MVC application, just for the purposes of cleaner looking code and more simplicity if there are lots of different methods.

I hope that makes sense, I'm finding it a little difficult to explain.

Edit:

Here's full example code:

this.browser.Navigating += (s, ev) =>
        {
            if (ev.Url.AbsoluteUri.Contains("app"))
            {
                var method = ev.Url.Host.Split('-')[1];
                var arguments = ev.Url.Query.TrimStart('?').Split('&');

                var dictionary = new Dictionary<string, string>();

                foreach (var arg in arguments)
                {
                    var split = arg.Split('=');

                    dictionary.Add(split[0], split[1]);
                }

                switch (method)
                {
                    case "add":
                        Add(Convert.ToInt32(dictionary["first"]), Convert.ToInt32(dictionary["second"]));
                        break;
                    default:                            
                        break;
                }

                ev.Cancel = true;
            }
        };

I figured out a really flexible way to do this using reflection and the JSON.net library. I changed the URL so that the parameters are passed as an HTML Encoded JSON. I loop through the required arguments and use the ToObject method of JSON.net to convert them to the required type. This even works when passing arrays and complex types.

var jsonString = HttpUtility.UrlDecode(ev.Url.Query.TrimStart('?'));

var json = JObject.Parse(jsonString);

var methodInfo = objWithMethodToRun.GetMethod(methodName);

var parameterInfoArray = methodInfo.GetParameters();
var parameters = new object[parameterInfoArray.Length];

//Add parameters as correct types to array.
for (var i = 0; i < parameterInfoArray.Length; i++)
{
    var methodParameterInfo = parameterInfoArray[i];

    //If there is nothing in the json we'll set it to null
    if (json[methodParameterInfo.Name] == null || json[methodParameterInfo.Name].Type == JTokenType.Null)
    {
        parameters[i] = null;
    }
    else
    {
        var convertMethod = json[methodParameterInfo.Name].GetType().GetMethod("ToObject", new Type[] { })
                            .MakeGenericMethod(methodParameterInfo.ParameterType);

        parameters[i] = convertMethod.Invoke(json[methodParameterInfo.Name], null);
    }
}

//Invoke the method
dynamic result = methodInfo.Invoke(objWithMethodToRun, parameters);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM