I am trying to create a ODataController and have it like so:
public class ProductSetController : ODataController
{
public IQueryable<ProductRef> GetAllProducts(string StoreId, string flag)
{
long lStoreId = Convert.ToInt64(StoreId);
var featuredProducts = (from b in new SomeContext().SomeInfluence
where b.SomeInfluenceTypeId == 1234 && b.StoreId == lStoreId && b.IsDeleted == false
select b.ProductId).ToList();
return (from b in new OProdctSubscriptionContext(lStoreId).ProductRef where featuredProducts.Contains(b.ProductId) select b).AsQueryable();
}
}
And this in WebApiConfig's Register method:
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<ProductRef>("ProductSet");
config.Routes.MapODataRoute("ODataRoute", "odata", builder.GetEdmModel());
To test it I made a call like so:
http://localhost:32944/odata/ProductSet/GetAllProducts?StoreId=5010&flag="N"
The browser printed out this error:
{"$id":"1","Message":"The OData path is
invalid.","ExceptionMessage":"Invalid action detected.
'GetAllProducts' is not an action that can bind to
'Collection([Entities.OpenApi.Products.ProductRef
Nullable=False])'.","ExceptionType":"Microsoft.Data.OData.ODataException","StackTrace":"
at
System.Web.Http.OData.Routing.DefaultODataPathHandler.ParseAtEntityCollection(IEdmModel
model, ODataPathSegment previous, IEdmType previousEdmType, String
segment)\r\n at
System.Web.Http.OData.Routing.DefaultODataPathHandler.ParseAtCollection(IEdmModel
model, ODataPathSegment previous, IEdmType previousEdmType, String
segment)\r\n at
System.Web.Http.OData.Routing.DefaultODataPathHandler.ParseNextSegment(IEdmModel
model, ODataPathSegment previous, IEdmType previousEdmType, String
segment)\r\n at
System.Web.Http.OData.Routing.DefaultODataPathHandler.Parse(IEdmModel
model, String odataPath)\r\n at
System.Web.Http.OData.Routing.ODataPathRouteConstraint.Match(HttpRequestMessage
request, IHttpRoute route, String parameterName, IDictionary`2 values,
HttpRouteDirection routeDirection)"}
What am I missing?
Any help is greatly appreciated.
Regards.
Just had this today.
Change
builder.EntitySet<ProductRef>("ProductSet");
to:
builder.EntitySet<ProductRef>().Collection.Action("GetAllProducts");
Add
[HttpPost]
public IQueryable<ProductRef> GetAllProducts(string StoreId, string flag)
This page helped me: http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/odata-actions
Related
After sending using [RelayCommand] in maui the setter in ViewModel receives truncated string in Maui.
Example orginal string: "https://twit.memberfulcontent.com/rss/9039?auth=m9FZurRandomAuthonumbers6yB"
The value of URL is good here:
[RelayCommand]
async Task Tap(string Url)
{
System.Diagnostics.Debug.WriteLine("Tap Sending: " + Url);
await Shell.Current.GoToAsync($"{nameof(ShowPage)}?Url={Url}");
}
when recieving here URL is truncated:
namespace NerdNewsNavigator2.ViewModel;
[QueryProperty("Url", "Url")]
public partial class ShowViewModel : ObservableObject
{
#region Properties
readonly TwitService _twitService;
public ObservableCollection<Show> Shows { get; set; } = new();
public string Url
{
set
{ // value is truncated string from Tap above.
System.Diagnostics.Debug.WriteLine("ShowViewModel Recieving url: " + value);
_ = GetShows(value);
OnPropertyChanged(nameof(Shows));
}
}
// Code shortened for brevity
Example of passed string:
"https://twit.memberfulcontent.com/rss/9039"
It gets truncated at ?Auth
Any suggestions on what I may be doing wrong? Or suggestion on a better way to do this? It works fine for string that do not have a ? mark in them. One hundred percent working except on this specific type of string.
I was expecting the string not to be truncated.
Correct way to pass data between pages in MAUI:
When you navigate:
Dictionary<string, object> query = new()
{
{ nameof(MyModel), myModel }
};
await Shell.Current.GoToAsync($"{nameof(MyPage)}", query);
When you are navigated:
public void ApplyQueryAttributes(IDictionary < string , object > query)
{
myModel = query[nameof(MyModel)] as MyModel;
}
(This solves more than the problem with sanitization)
I made a grid helper in App_Code called ControlHelper and it works just fine. I renders a form and a table with inputs and has buttons to submit all the information back to a method of my choosing.
I can tell that the controller code to handle the submits off this grid is going to be the same every time, so I added a method called Submit() onto my helper to reuse that code.
I can successfully call the helper method to render the grid from my view with
#ControlHelper.Grid(Html, Model, "About", "Home")
But when I try to call ControlHelper.Submit() from my controller code it says my helper is undefined.
The name 'ControlHelper' does not exist in the current context
Here's the relevant part of the code of the helper:
#using System.Web.Mvc;
#using System.Web.Mvc.Html;
#using male.services.biz
#functions
{
public static HelperResult Grid<TModel, T>(HtmlHelper<TModel> html,
EFCollection<T> collection,
string action,
string controller,
FormMethod method = FormMethod.Post,
string formName = null) where T : EFObject<T>
{
formName = formName ?? "frm" + typeof(T).Name + "s";
return RenderGrid(html, typeof(T), collection, action, controller, method, formName);
}
public static void Submit<T>(EFCollection<T> collection, string save, string add, string delete) where T : EFObject<T>
{
if (add == null)
collection.Remove(collection.Last());
if (delete != null)
{
var itemToDelete = collection[int.Parse(delete)];
collection.Remove(itemToDelete);
itemToDelete.Delete();
}
if (add != null || delete != null || save != null)
collection.Save();
}
}
My controller code currently is:
[HttpPost]
public ActionResult About(EFCollection<Member> members, string save, string add, string delete)
{
if (add == null)
members.Remove(members.Last());
if (delete != null)
{
var memberToDelete = members[int.Parse(delete)];
members.Remove(memberToDelete);
memberToDelete.Delete();
}
if (add != null || delete != null || save != null)
members.Save();
return View(members);
}
but see if I can get this to work it will reduce to just:
[HttpPost]
public ActionResult About(EFCollection<Member> members, string save, string add, string delete)
{
ControlHelper.Submit(members, save, add, delete);
return View(members);
}
The answer is, I don't do this like this any more. I use shared edit / display views for certain types and classes to achieve what I want.
thank you for your reply,
i added BeginExecuteCore in base controller like this
`public class BaseController : Controller
{
protected override IAsyncResult BeginExecuteCore(AsyncCallback callback, object state)
{
//string email = string.Empty;
dbEntities dbcontext = new dbEntities();
var userRoleName = (from n in dbcontext.VAgentClientEmails where n.Email == User.Identity.Name select n.Role).FirstOrDefault();
if (userRoleName == "SuperAdmin")
RouteData.Values["role"] = userRoleName;
else
RouteData.Values["role"] = "";
return base.BeginExecuteCore(callback, state);
}`
and i have given in home controller like this
[Route("~/{role}/SavedSearch/Index")]
public ActionResult Index()
{
...
}
its working for admin/savedsearch/index
and also if i give fjsdfk/savedsearch/index its working
in the above case it should not work..
and in else case i dont want role
do i need to do any changes?
I've set attribute routing on a controller class which inherits a base class where I handle I18N culture set/selection logic (as described in article ASP.NET MVC 5 Internationalization) but that process fails, although route seemed to be set correctly.
[RoutePrefix("{culture}")]
public class HomeController : BaseController
{
public ActionResult Index()
{
return View();
}
[Route("Hakkimda")]
public ActionResult About()
{
ViewBag.Message = "Your application description page.";
return View();
}
When I try to get to link I see grey screen of death on browser with this on address bar:
http://localhost:53530/tr-tr/Hakkimda?MS_DirectRouteMatches=System.Collections.Generic.List%601%5BSystem.Web.Routing.RouteData%5D
I believe the problem is the way base controller implements I18N logic which is based on BeginExecuteCore overloading.
protected override IAsyncResult BeginExecuteCore(AsyncCallback callback, object state)
{
string cultureName = RouteData.Values["culture"] as string;
// Attempt to read the culture cookie from Request
if (cultureName == null)
cultureName = Request.UserLanguages != null && Request.UserLanguages.Length > 0 ? Request.UserLanguages[0] : null; // obtain it from HTTP header AcceptLanguages
// Validate culture name
cultureName = CultureHelper.GetImplementedCulture(cultureName); // This is safe
if (RouteData.Values["culture"] as string != cultureName) {
// Force a valid culture in the URL
RouteData.Values["culture"] = cultureName.ToLowerInvariant(); // lower case too
// Redirect user
Response.RedirectToRoute(RouteData.Values);
}
// Modify current thread's cultures
Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(cultureName);
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;
return base.BeginExecuteCore(callback, state);
}
Probably execution precedence of BeginExecuteCore and routing have some mismatch but my knowledge on both don't suffice to solve it.
I've seen this article(What’s New in ASP.NET MVC 5.2 : Attribute routing improvements) but example provided there was a bit different and because it's new there aren't other examples on the net.
mr-anton's answer will stop you getting rubbish in the address bar but It'll also stop the language changing.
I had this issue after a change from MVC5 to MVC5.2
This answer says it is a Microsoft issue
The workaround is to see if the route data is in a nested route key
var routeData = RouteData;
if (routeData.Values.ContainsKey("MS_DirectRouteMatches"))
{
routeData = ((IEnumerable<System.Web.Routing.RouteData>)routeData.Values["MS_DirectRouteMatches"]).First();
}
string cultureName = routeData.Values["culture"] as string;
And then it just works.
remove this code
if (RouteData.Values["culture"] as string != cultureName) {
// Force a valid culture in the URL
RouteData.Values["culture"] = cultureName.ToLowerInvariant(); // lower case too
// Redirect user
Response.RedirectToRoute(RouteData.Values);
}
I have the following code on server:
public class UploadController : ApiController
{
public void Put(string filename, string description)
{
...
}
public void Put()
{
...
}
and try to call it from client:
var clientDescr = new HttpClient();
var postData = new List<KeyValuePair<string, string>>();
postData.Add(new KeyValuePair<string, string>("filename", "test"));
postData.Add(new KeyValuePair<string, string>("description", "100"));
HttpContent contentDescr = new FormUrlEncodedContent(postData);
clientDescr.PutAsync("http://localhost:8758/api/upload", contentDescr).ContinueWith(
(postTask) =>
{
postTask.Result.EnsureSuccessStatusCode();
});
but this code calls second put method (without parameters). Why and how to call first put method correctly?
You have several options here:
You can either choose to pass the parameters in the query string, by just changing the URI to:
http://localhost:8758/api/upload?filename=test&description=100
or you can have Web API parse the form data for you by changing your action to look like this:
public void Put(FormDataCollection formData)
{
string fileName = formData.Get("fileName");
string description = formData.Get("description");
}
You can also choose to create a class that has a fileName and a description property and use that as your parameter and Web API should be able to bind it correctly for you.