I completely agree with the advice around using view models where possible. They are much easier to work with, even if they can seem overkill at times.
That said, to answer your question, you could use a Tuple for this:
public IActionResult Test(string id)
{
var user = context.Users.First(x => x.Id.ToString() == id);
var message = "abc";
// The generic types will be inferred here so they're not necessary
// but I've added them for clarity in the example.
var viewModel = Tuple.Create<User, string>(user, message);
return View("Edit", viewModel);
}
Then in the view, you'll need this:
@model Tuple<User, string>
Just make sure to add the correct namespace to the User type in the view.
Edit
For completeness, here's an example of using a ValueTuple from C# 7, following Adam's comment below:
public IActionResult Test(string id)
{
var user = context.Users.First(x => x.Id.ToString() == id);
var message = "abc";
return View("Edit", (user, message));
}
If you're using .NET Core 2.1 and above, the view's model directive becomes:
@model (User user, string message)
You'd then access those like so:
@Model.user
Otherwise, you'll need to use (credit to @AdamSimon from the comments):
@model ValueTuple<User, string>
var (user, message) = Model;
See the What's New in C# 7.0 blog post on MSDN for more information.
ViewBag