9
\$\begingroup\$

I need to pass an array of values in Url.Action.

Currently I'm doing:

var redirectUrl = Url.Action("search", new {   
        q = criteria.Q,
        advanced = criteria.Advanced,
        salaryfrom = criteria.SalaryFrom,
        salaryto = criteria.SalaryTo,
    });

if (criteria.JobTypes != null)
    redirectUrl += criteria.JobTypes.Aggregate(string.Empty, (a, x) => a += "&jobTypes=" + x);

To give me something like:

/search?q=developer&advanced=false&salaryfrom=20000&salaryto=80000&jobTypes=Full%20Time&jobTypes=Contract

Is there a nicer/cleaner approach?

\$\endgroup\$
5
\$\begingroup\$

I assume you "own" the controller? If so, I'd serialize and deserialize the list as a comma separated string on each side. It'd also be nice if criteria.JobTypes is an empty list instead of a possible null, then you don't need the ?? below.

var redirectUrl = Url.Action("search", new {
    // ...
    jobTypes = String.Join(criteria.JobTypes ?? new string[0], ",")
}

And do jobTypes.split(",") in the action.

URL would look a bit nicer too:

/search?q=developer&advanced=false&salaryfrom=20000&salaryto=80000&jobTypes=Full%20Time,Contract
| improve this answer | |
\$\endgroup\$
4
\$\begingroup\$

To expand on Lars-Erik's answer, you can also use the other overload, the one that takes a dictionary.
This is also useful to construct e.g. an input that might or might not be disabled.

RouteValueDictionary args = new RouteValueDictionary {
    {"q", criteria.Q},
    {"advanced", criteria.Advanced},
    {"salaryfrom", criteria.SalaryFrom},
    {"salaryto", criteria.SalaryTo},
};
if(criteria.JobTypes != null) {
    // Either foreach the jobTypes or go Lars-Erik's way (nicer).
    args.Add("jobTypes", "foo");
}

Take care about special characters!
If you don't fully control the input, you might get a jobType "R&D" that will break your url: /search?q=...&jobTypes=R&D gets you jobTypes=R.

| improve this answer | |
\$\endgroup\$
3
\$\begingroup\$

You can add the array elements individually to the RouteValueDictionary -- you just have to change the name to match the model binding name for round trip purposes.

The second argument to your action can be a RouteValueDictionary as ANeves said.

RouteValueDictionary rvd = new RouteValueDictionary { { "name", "value"}, ...};
int i = 0;
criteria.JobTypes.ForEach(v => rvd.Add(String.Format("jobTypes[{0}]", i++), (object) v));
| improve this answer | |
\$\endgroup\$
2
\$\begingroup\$

Instead of Type Casting to 'objectorobject[]or usingRouteValueDictionary`. A simple way to achieve the same is using “Newtonsoft.Json”

If using .Net Core 3.0 or later;

Default to using the built in System.Text.Json parser implementation.

@using System.Text.Json;

…….

@Url.Action(“ActionName”, “ControllerName”, new {object = JsonConvert.SerializeObject(‘@ModalObject’)  }))

If stuck using .Net Core 2.2 or earlier;

Default to using Newtonsoft JSON.Net as your first choice JSON Parser.

@using Newtonsoft.Json;

…..

@Url.Action(“ActionName”, “ControllerName”, new {object = JsonConvert.SerializeObject(‘@ModalObject’)  }))

you may need to install the package first.

PM> Install-Package Newtonsoft.Json

Then,

public ActionResult ActionName(string modalObjectJSON)
{
    Modal modalObj = new Modal();
    modalObj = JsonConvert.DeserializeObject<Modal>(modalObjectJSON);

}
| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.