Exception in HttpControllerDispatcher - asp.net-web-api

In my WebApiConfig::Register(...) I replaced the HttpControllerSelector with my own controller selector. When I fire off a POST request the SelectController member is correctly called and I return a ControllerDescriptor with the correct type of my controller.
But then HttpControllerDispatcher is raising an exception saying "The given was not present in the dictionary." Anyone has an idea how to debug such error?
The complete exception is message is:
The given key was not present in the dictionary.","ExceptionType":"System.Collections.Generic.KeyNotFoundException","StackTrace":" at System.Collections.Generic.Dictionary`2.get_Item(TKey key)\r\n
at System.Web.Http.Controllers.ApiControllerActionSelector.ActionSelectorCacheItem.FindActionMatchRequiredRouteAndQueryParameters(IEnumerable`1 candidatesFound)\r\n
at System.Web.Http.Controllers.ApiControllerActionSelector.ActionSelectorCacheItem.FindMatchingActions(HttpControllerContext controllerContext, Boolean ignoreVerbs)\r\n
at System.Web.Http.Controllers.ApiControllerActionSelector.ActionSelectorCacheItem.SelectAction(HttpControllerContext controllerContext)\r\n
at System.Web.Http.Controllers.ApiControllerActionSelector.SelectAction(HttpControllerContext controllerContext)\r\n
at System.Web.Http.ApiController.ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken)\r\n
at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()"
And here is my Controller Selector:
public class Namespace_HTTP_Controller_Selector : IHttpControllerSelector
{
private readonly HttpConfiguration _configuration;
private readonly Lazy<Dictionary<string, HttpControllerDescriptor>> _controller;
public Namespace_HTTP_Controller_Selector(HttpConfiguration Config)
{
_configuration = Config;
_controller = new Lazy<Dictionary<string, HttpControllerDescriptor>>(Initialize_Controller_Dictionary);
}
public HttpControllerDescriptor SelectController(HttpRequestMessage Request)
{
var Route_Data = Request.GetRouteData();
if(Route_Data == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
var Controller_Name = Get_Controller_Name(Route_Data);
if(Controller_Name == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
var Name_Space = Get_Version(Route_Data);
if (Name_Space == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
var Controller_Key = String.Format(CultureInfo.InvariantCulture, "{0}.{1}", Name_Space, Controller_Name);
HttpControllerDescriptor Descriptor;
if(_controller.Value.TryGetValue(Controller_Key, out Descriptor))
{
return Descriptor;
}
throw new HttpResponseException(HttpStatusCode.NotFound);
}
public IDictionary<string, HttpControllerDescriptor> GetControllerMapping()
{
return _controller.Value;
}
private Dictionary<string, HttpControllerDescriptor> Initialize_Controller_Dictionary()
{
var Dictionary = new Dictionary<string, HttpControllerDescriptor>(StringComparer.OrdinalIgnoreCase);
var Assemblies_Resolver = _configuration.Services.GetAssembliesResolver();
var Controller_Resolver = _configuration.Services.GetHttpControllerTypeResolver();
var Controller_Types = Controller_Resolver.GetControllerTypes(Assemblies_Resolver);
foreach(var ct in Controller_Types)
{
var Segments = ct.Namespace.Split(Type.Delimiter);
var Controller_Name = ct.Name.Remove(ct.Name.Length - DefaultHttpControllerSelector.ControllerSuffix.Length);
var Controller_Key = string.Format(CultureInfo.InvariantCulture, "{0}.{1}", Segments[Segments.Length - 1], Controller_Name);
if(Dictionary.Keys.Contains(Controller_Key) == false)
{
Dictionary[Controller_Key] = new HttpControllerDescriptor(_configuration, ct.Name, ct);
}
}
return Dictionary;
}
private T Get_Route_Variable<T>(IHttpRouteData Route_Data, string Name)
{
object Result;
if(Route_Data.Values.TryGetValue(Name, out Result))
{
return (T)Result;
}
return default(T);
}
private string Get_Controller_Name(IHttpRouteData Route_Data)
{
var SubRoute = Route_Data.GetSubRoutes().FirstOrDefault();
if( SubRoute == null )
{
return null;
}
var Data_Token_Value = SubRoute.Route.DataTokens.First().Value;
if(Data_Token_Value == null)
{
return null;
}
var Controller_Name = ((HttpActionDescriptor[])Data_Token_Value).First().ControllerDescriptor.ControllerName.Replace("Controller", string.Empty);
return Controller_Name;
}
private string Get_Version(IHttpRouteData Route_Data)
{
var Sub_Route_Data = Route_Data.GetSubRoutes().FirstOrDefault();
if(Sub_Route_Data== null)
{
return null;
}
return Get_Route_Variable<string>(Sub_Route_Data, "apiVersion");
}
}

This is because you are not setting subroute data in request before returning descriptor.
HttpControllerDescriptor Descriptor;
if(_controller.Value.TryGetValue(Controller_Key, out Descriptor))
{
var subRoutes = Route_Data.GetSubRoutes();
IEnumerable<IHttpRouteData> filteredSubRoutes = subRoutes.Where(attrRouteData =>
{
HttpControllerDescriptor currentDescriptor = ((HttpActionDescriptor[])Route_Data.Route.DataTokens["actions"]).First().ControllerDescriptor;
return currentDescriptor != null && currentDescriptor.ControllerName.Equals(Descriptor.ControllerName, StringComparison.OrdinalIgnoreCase);
});
Route_Data.Values["MS_SubRoutes"] = filteredSubRoutes.ToArray();
return Descriptor;
}
Take a look at:
Versioning ASP.NET Web API 2 with Media Types

public class CustomSelectorController : DefaultHttpControllerSelector
{
HttpConfiguration _config;
public CustomSelectorController(HttpConfiguration config) : base(config)
{
_config = config;
}
public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
{
IHttpRouteData routeData = request.GetRouteData();
IEnumerable<IHttpRouteData> attributeSubRoutes = routeData.GetSubRoutes();
var actions = attributeSubRoutes.LastOrDefault()?.Route?.DataTokens["actions"] as HttpActionDescriptor[];
var controllerName = "";
if (actions != null && actions.Length > 0)
{
controllerName = actions[0].ControllerDescriptor.ControllerName;
}
IEnumerable<string> headerValues = null;
//Custom Header Name to be check version
if (request.Headers.TryGetValues("Accept-Version", out headerValues))
{
var apiVersion = headerValues.First().ToUpper();
if (apiVersion == "V2")
{
controllerName = controllerName + apiVersion;
}
}
HttpControllerDescriptor controllerDescriptor = null;
IEnumerable<IHttpRouteData> filteredSubRoutes = attributeSubRoutes.Where(attrRouteData =>
{
HttpControllerDescriptor currentDescriptor = GetControllerDescriptor(attrRouteData);
bool match = currentDescriptor.ControllerName.Equals(controllerName);
if (match && (controllerDescriptor == null))
{
controllerDescriptor = currentDescriptor;
}
return match;
});
routeData.Values["MS_SubRoutes"] = filteredSubRoutes.ToArray();
return controllerDescriptor;
}
private HttpControllerDescriptor GetControllerDescriptor(IHttpRouteData routeData)
{
return ((HttpActionDescriptor[])routeData.Route.DataTokens["actions"]).First().ControllerDescriptor;
}
}

Related

how to implement Android In App BillingClient in Xamarin.Android Asynchronously

I am trying to implement below java code in c# referring to Android documentation
List<String> skuList = new ArrayList<> ();
skuList.add("premium_upgrade");
skuList.add("gas");
SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder();
params.setSkusList(skuList).setType(SkuType.INAPP);
billingClient.querySkuDetailsAsync(params.build(),
new SkuDetailsResponseListener() {
#Override
public void onSkuDetailsResponse(BillingResult billingResult,
List<SkuDetails> skuDetailsList) {
// Process the result.
}
});
I have here 2 questions. I thought that i would run this code on a separate thread than UI thread like below to keep my ui responsive while network connection is done. is that the correct approach? QuerySkuDetailsAsync is called async but doesnt implement as async. how should this be working and how to handle in c# because it will fire and forget but Listener to handle the response.
public async Task<List<InAppBillingProduct>> GetProductsAsync(List<string> ProductIds)
{
var getSkuDetailsTask = Task.Factory.StartNew(() =>
{
var prms = SkuDetailsParams.NewBuilder();
var type = BillingClient.SkuType.Inapp;
prms.SetSkusList(ProductIds).SetType(type);
BillingClient.QuerySkuDetailsAsync(prms.Build(), new SkuDetailsResponseListener());
return InAppBillingProducts;
});
return await getSkuDetailsTask;
}
2nd question regarding how to handle with the listener as below. How do I return value from the listener. I need return list of InAppBillingProduct object.
public class SkuDetailsResponseListener : Java.Lang.Object, ISkuDetailsResponseListener
{
public void OnSkuDetailsResponse(BillingResult billingResult, IList<SkuDetails> skus)
{
if (billingResult.ResponseCode == BillingResponseCode.Ok)
{
// get list of Products here and return
}
}
}
FYI. This is how I did it. This is not a complete code but this will give you and idea.
Listener - PCL
============
private async Task EventClicked()
{
var skuList = new List<string>();
skuList.Add("[nameofsubscriptionfoundinyourgoogleplay]");
if (await _billingClientLifecycle.Initialize(skuList, DisconnectedConnection))
{
var firstProduct = _billingClientLifecycle?.ProductsInStore?.FirstOrDefault();
if (firstProduct != null)
{
//purchase here
}
}
}
private void DisconnectedConnection()
{
//Todo.alfon. handle disconnection here...
}
Interface - PCL
===========
public interface IInAppBillingMigratedNew
{
List<InAppBillingPurchase> PurchasedProducts { get; set; }
List<InAppBillingProduct> ProductsInStore { get; set; }
Task<bool> Initialize(List<String> skuList, Action onDisconnected = null);
}
Dependency - Platform Droid
===============
[assembly: XF.Dependency(typeof(InAppBillingMigratedNew))]
public class InAppBillingMigratedNew : Java.Lang.Object, IBillingClientStateListener
, ISkuDetailsResponseListener, IInAppBillingMigratedNew
{
private Activity Context => CrossCurrentActivity.Current.Activity
?? throw new NullReferenceException("Current Context/Activity is null");
private BillingClient _billingClient;
private List<string> _skuList = new List<string>();
private TaskCompletionSource<bool> _tcsInitialized;
private Action _disconnectedAction;
private Dictionary<string, SkuDetails> _skusWithSkuDetails = new Dictionary<string, SkuDetails>();
public List<InAppBillingPurchase> PurchasedProducts { get; set; }
public List<InAppBillingProduct> ProductsInStore { get; set; }
public IntPtr Handle => throw new NotImplementedException();
public Task<bool> Initialize(List<string> skuList, Action disconnectedAction = null)
{
_disconnectedAction = disconnectedAction;
_tcsInitialized = new TaskCompletionSource<bool>();
var taskInit = _tcsInitialized.Task;
_skuList = skuList;
_billingClient = BillingClient.NewBuilder(Context)
.SetListener(this)
.EnablePendingPurchases()
.Build();
if (!_billingClient.IsReady)
{
_billingClient.StartConnection(this);
}
return taskInit;
}
#region IBillingClientStateListener
public void OnBillingServiceDisconnected()
{
Console.WriteLine($"Connection disconnected.");
_tcsInitialized?.TrySetResult(false);
_disconnectedAction?.Invoke();
}
public void OnBillingSetupFinished(BillingResult billingResult)
{
var responseCode = billingResult.ResponseCode;
var debugMessage = billingResult.DebugMessage;
if (responseCode == BillingResponseCode.Ok)
{
QuerySkuDetails();
QueryPurchases();
_tcsInitialized?.TrySetResult(true);
}
else
{
Console.WriteLine($"Failed connection {debugMessage}");
_tcsInitialized?.TrySetResult(false);
}
}
#endregion
#region ISkuDetailsResponseListener
public void OnSkuDetailsResponse(BillingResult billingResult, IList<SkuDetails> skuDetailsList)
{
if (billingResult == null)
{
Console.WriteLine("onSkuDetailsResponse: null BillingResult");
return;
}
var responseCode = billingResult.ResponseCode;
var debugMessage = billingResult.DebugMessage;
switch (responseCode)
{
case BillingResponseCode.Ok:
if (skuDetailsList == null)
{
_skusWithSkuDetails.Clear();
}
else
{
if (skuDetailsList.Count > 0)
{
ProductsInStore = new List<InAppBillingProduct>();
}
foreach (var skuDetails in skuDetailsList)
{
_skusWithSkuDetails.Add(skuDetails.Sku, skuDetails);
//ToDo.alfon. make use mapper here
ProductsInStore.Add(new InAppBillingProduct
{
Name = skuDetails.Title,
Description = skuDetails.Description,
ProductId = skuDetails.Sku,
CurrencyCode = skuDetails.PriceCurrencyCode,
LocalizedIntroductoryPrice = skuDetails.IntroductoryPrice,
LocalizedPrice = skuDetails.Price,
MicrosIntroductoryPrice = skuDetails.IntroductoryPriceAmountMicros,
MicrosPrice = skuDetails.PriceAmountMicros
});
}
}
break;
case BillingResponseCode.ServiceDisconnected:
case BillingResponseCode.ServiceUnavailable:
case BillingResponseCode.BillingUnavailable:
case BillingResponseCode.ItemUnavailable:
case BillingResponseCode.DeveloperError:
case BillingResponseCode.Error:
Console.WriteLine("onSkuDetailsResponse: " + responseCode + " " + debugMessage);
break;
case BillingResponseCode.UserCancelled:
Console.WriteLine("onSkuDetailsResponse: " + responseCode + " " + debugMessage);
break;
// These response codes are not expected.
case BillingResponseCode.FeatureNotSupported:
case BillingResponseCode.ItemAlreadyOwned:
case BillingResponseCode.ItemNotOwned:
default:
Console.WriteLine("onSkuDetailsResponse: " + responseCode + " " + debugMessage);
break;
}
}
#endregion
#region Helper Methods Private
private void ProcessPurchases(List<Purchase> purchasesList)
{
if (purchasesList == null)
{
Console.WriteLine("No purchases done.");
return;
}
if (IsUnchangedPurchaseList(purchasesList))
{
Console.WriteLine("Purchases has not changed.");
return;
}
_purchases.AddRange(purchasesList);
PurchasedProducts = _purchases.Select(sku => new InAppBillingPurchase
{
PurchaseToken = sku.PurchaseToken
})?.ToList();
if (purchasesList != null)
{
LogAcknowledgementStatus(purchasesList);
}
}
private bool IsUnchangedPurchaseList(List<Purchase> purchasesList)
{
// TODO: Optimize to avoid updates with identical data.
return false;
}
private void LogAcknowledgementStatus(List<Purchase> purchasesList)
{
int ack_yes = 0;
int ack_no = 0;
foreach (var purchase in purchasesList)
{
if (purchase.IsAcknowledged)
{
ack_yes++;
}
else
{
ack_no++;
}
}
//Log.d(TAG, "logAcknowledgementStatus: acknowledged=" + ack_yes +
// " unacknowledged=" + ack_no);
}
private void QuerySkuDetails()
{
var parameters = SkuDetailsParams
.NewBuilder()
.SetType(BillingClient.SkuType.Subs)
.SetSkusList(_skuList)
.Build();
_billingClient.QuerySkuDetailsAsync(parameters, this);
}
private void QueryPurchases()
{
if (!_billingClient.IsReady)
{
Console.WriteLine("queryPurchases: BillingClient is not ready");
}
var result = _billingClient.QueryPurchases(BillingClient.SkuType.Subs);
ProcessPurchases(result?.PurchasesList?.ToList());
}
#endregion
}

Is How do I solve the error Event registration is overwriting existing delegate for MKMapView?

When I try to run my Xamarin.forms maps application I get the following error: Event registration is overwriting existing delegate. Either just use events or your own delegate: MyApp.iOS.CustomRenderer.MapDelegate MapKit.MKMapView+_MKMapViewDelegate
I attached my CustomMapRender file to this question
... C#
using ICCHMapClusterControllerDelegate = MapClustering.ICCHMapClusterControllerDelegate;
using ICCHMapClusterer = MapClustering.ICCHMapClusterer;
[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace MyApp.iOS.CustomRenderer
{
public class CustomMapRenderer : MapRenderer, ICCHMapClusterControllerDelegate//IMKMapViewDelegate
{
MKMapView mapView;
CustomMap customMap;
CCHMapClusterController mapClusterController;
ICCHMapClusterer mapClusterer;
List<MKPointAnnotation> annotations;
CLLocationManager LocationManager;
protected override void Dispose(bool disposing)
{
mapView.ShowsUserLocation = false;
base.Dispose(disposing);
}
protected override void OnElementChanged(ElementChangedEventArgs<View> e)
{
base.OnElementChanged(e);
if (e.OldElement == null)
{
mapView = Control as MKMapView;
customMap = e.NewElement as CustomMap;
customMap.LocationsLoaded += customMap_LocationsLoaded;
customMap.CenterToMyLocationButtonClicked += CenterToMyLocation;
customMap.OpenCallout += OpenCallout;
LocationManager = new CLLocationManager();
LocationManager.AuthorizationChanged += (object locationmanager, CLAuthorizationChangedEventArgs eventargs) =>
{
if (eventargs.Status == CLAuthorizationStatus.AuthorizedWhenInUse)
{
mapView.ShowsUserLocation = true;
}
else
{
mapView.ShowsUserLocation = false;
}
};
if (CLLocationManager.Status == CLAuthorizationStatus.AuthorizedWhenInUse || CLLocationManager.Status == CLAuthorizationStatus.AuthorizedAlways
|| CLLocationManager.Status == CLAuthorizationStatus.Authorized)
{
mapView.ShowsUserLocation = true;
}
WMSTileOverlay WMSOverlay = new WMSTileOverlay(NetworkConstants.WmsOvermaasLayerUrl, "3")
{
CanReplaceMapContent = false
};
WMSProvincieTileOverlay ProvinceOverLay = new WMSProvincieTileOverlay
{
CanReplaceMapContent = false
};
WMSTileOverlay WPMOverlay2 = new WMSTileOverlay(NetworkConstants.WmsWpmLayerUrl, "2")
{
CanReplaceMapContent = false
};
WMSTileOverlay WPMOverlay3 = new WMSTileOverlay(NetworkConstants.WmsWpmLayerUrl, "3")
{
CanReplaceMapContent = false
};
WMSTileOverlay WPMOverlay4 = new WMSTileOverlay(NetworkConstants.WmsWpmLayerUrl, "4")
{
CanReplaceMapContent = false
};
mapView.AddOverlay(WMSOverlay, MKOverlayLevel.AboveLabels);
mapView.AddOverlay(ProvinceOverLay, MKOverlayLevel.AboveLabels);
mapView.AddOverlay(WPMOverlay2, MKOverlayLevel.AboveLabels);
mapView.AddOverlay(WPMOverlay3, MKOverlayLevel.AboveLabels);
mapView.AddOverlay(WPMOverlay4, MKOverlayLevel.AboveLabels);
Debug.WriteLine("TESTING");
mapClusterController = new CCHMapClusterController(mapView);
mapClusterController.Delegate = new CCHMapClusterControllerDelegate();
mapClusterController.WeakDelegate = this;
// /new CCHMapDelegate();//new CCHMapDelegate();
//new CCHMapClusterControllerDelegate(); //new CCHMapDelegate ();
}
}
private void customMap_LocationsLoaded(object sender, List<Location> locations)
{
RemoveAnnotations();
if (locations == null || locations.Count == 0)
{
return;
}
annotations = new List<MKPointAnnotation>();
foreach (Location location in locations)
{
MKPointAnnotation anno = new MKPointAnnotation();
CLLocationCoordinate2D coord = new CLLocationCoordinate2D(location.Latitude, location.Longitude);
anno.Coordinate = coord;
anno.Title = location.WaterName;
anno.Subtitle = location.City + " " + location.ExternalReference;
annotations.Add(anno);
}
mapClusterController.AddAnnotations(annotations.ToArray(), null);
mapView.Delegate = new MapDelegate(locations, customMap);
mapClusterController.ReuseExistingClusterAnnotations = false;
}
private void RemoveAnnotations()
{
if (annotations != null && annotations.Count != 0)
{
mapClusterController.RemoveAnnotations(annotations.ToArray(), () =>
{
});
}
}
private void CenterToMyLocation(object sender, string e)
{
if (CLLocationManager.Status == CLAuthorizationStatus.AuthorizedWhenInUse || CLLocationManager.Status == CLAuthorizationStatus.AuthorizedAlways
|| CLLocationManager.Status == CLAuthorizationStatus.Authorized)
{
MKCoordinateRegion mapRegion;
mapRegion.Center.Latitude = mapView.UserLocation.Coordinate.Latitude;
mapRegion.Center.Longitude = mapView.UserLocation.Coordinate.Longitude;
mapRegion.Span.LatitudeDelta = 0.2;
mapRegion.Span.LongitudeDelta = 0.2;
mapView.SetRegion(mapRegion, true);
}
if (CLLocationManager.Status == CLAuthorizationStatus.Denied)
{
//check if ios 7/8 this is ios 8
UIAlertController alertController = UIAlertController.Create(title: "Locatie", message: "Om uw locatie te kunnen gebruiken in de app hebben we uw toestemming nodig. " +
"dit kunt u in het instellingen menu geven.", preferredStyle: UIAlertControllerStyle.Alert);
alertController.AddAction(UIAlertAction.Create(title: "Annuleren", style: UIAlertActionStyle.Cancel, handler: null));
alertController.AddAction(UIAlertAction.Create(title: "Instellingen", style: UIAlertActionStyle.Default, handler =>
{
NSUrl settingsurl = new NSUrl(UIApplication.OpenSettingsUrlString);
mapView.ShowsUserLocation = true;
UIApplication.SharedApplication.OpenUrl(settingsurl);
}));
UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewController(alertController, true, null);
//Old Obsolete
//UIAlertView alert = new UIAlertView("Locatie", "Om uw locatie te kunnen gebruiken in de app hebben we uw toestemming nodig. " +
// "dit kunt u in het instellingen menu geven.", null, "Annuleren", "Instellingen");
//alert.Clicked += (object alertsender, UIButtonEventArgs eventargs) => {
// if (eventargs.ButtonIndex != 0)
// {
// NSUrl settingsurl = new NSUrl(UIApplication.OpenSettingsUrlString);
// mapView.ShowsUserLocation = true;
// UIApplication.SharedApplication.OpenUrl(settingsurl);
// }
//};
//alert.Show();
}
if (CLLocationManager.Status == CLAuthorizationStatus.NotDetermined)
{
LocationManager.RequestWhenInUseAuthorization();
}
}
private void OpenCallout(object sender, Location e)
{
System.Threading.Tasks.Task.Factory.StartNew(() =>
{
Thread.Sleep(1000); // delay execution for 1 s
Device.BeginInvokeOnMainThread(() =>
{
var anno = this.annotations.Where(a => a.Coordinate.Latitude == e.Latitude && a.Coordinate.Longitude == e.Longitude).FirstOrDefault();
if (anno != null)
{
this.mapClusterController.SelectAnnotation(anno, e.Latitude, e.Longitude);
}
});
});
}
[Export("mapClusterController:titleForMapClusterAnnotation:")]
public string TitleForMapClusterAnnotation(CCHMapClusterController mapClusterController, CCHMapClusterAnnotation mapClusterAnnotation)
{
var annotationsCount = mapClusterAnnotation.Annotations.Count;
if (annotationsCount != 1) return "";
MKPointAnnotation annot = (MKPointAnnotation)mapClusterAnnotation.Annotations.First();
return annot.Title;
}
[Export("mapClusterController:subtitleForMapClusterAnnotation:")]
public string SubtitleForMapClusterAnnotation(CCHMapClusterController mapClusterController, CCHMapClusterAnnotation mapClusterAnnotation)
{
if (mapClusterAnnotation.Annotations.Count != 1) return "";
MKPointAnnotation annot = (MKPointAnnotation)mapClusterAnnotation.Annotations.First();
return annot.Subtitle;
}
[Export("mapClusterController:willReuseMapClusterAnnotation:")]
public void WillReuseMapClusterAnnotation(CCHMapClusterController mapClusterController, CCHMapClusterAnnotation mapClusterAnnotation)
{
}
}
internal class MapDelegate : MKMapViewDelegate
{
public MapDelegate(List<Location> locations, CustomMap CustomMap)
: base()
{
Locations = locations;
customMap = CustomMap;
conv = new LevelStatusToColorValueConverter();
defaultColor = Color.FromHex(ColorConstants.WaterLevelBadgeGreen).ToUIColor();
}
static NSObject Invoker = new NSObject();
List<Location> Locations;
string clusterPinId = "cluster";
string nonClusterPinId = "nonCluster";
CustomMap customMap;
LevelStatusToColorValueConverter conv;
UIColor defaultColor;
public override void RegionChanged(MKMapView mapView, bool animated)
{
if (mapView.UserLocationVisible)
{
customMap.ChangeStatusOfLocationImageOnMap(true);
}
else
{
customMap.ChangeStatusOfLocationImageOnMap(false);
}
}
public override MKAnnotationView GetViewForAnnotation(MKMapView mapView, IMKAnnotation anno)
{
var annotation = ObjCRuntime.Runtime.GetNSObject(anno.Handle) as CCHMapClusterAnnotation; // this is required to get the underlying annotation object
string useId = nonClusterPinId;
if (anno is MKUserLocation)
return null;
if (annotation == null)
{
return null;
}
string imageName = "";
string imageURL = string.Empty;
string value = string.Empty;
UIColor color = defaultColor;
if (annotation.IsCluster)
{
useId = clusterPinId;
if (Locations != null)
{
List<Location> locations = new List<Location>();
foreach (MKPointAnnotation clusterAnno in annotation.Annotations)
{
string title = clusterAnno.Subtitle;
var location = Locations.Where(l => (l.City + " " + l.ExternalReference) == title).ToList();
if (location != null && location.Count != 0)
{
locations.Add(location.First());
}
}
if (locations.Any())
{
imageName = MapUtil.GetCorrectImageNameForLocations(locations);
}
}
}
else
{
if (Locations != null)
{
string title = annotation.Subtitle;
var location = Locations.Where(l => (l.City + " " + l.ExternalReference) == title).ToList();
if (location != null && location.Count != 0)
{
var currentLocation = location.First();
value = currentLocation.CurrentValueAsString;
var xColor = (Color)conv.Convert(currentLocation.WaterlevelStatus, null, null, null);
color = xColor.ToUIColor();
imageName = MapUtil.GetCorrectImageNameForLocation(currentLocation);
if (currentLocation.HasImage)
{
imageURL = currentLocation.SmallImageURL();
}
else
{
imageURL = NetworkConstants.NoImageSmall;
}
}
}
}
MKAnnotationView pinView = (MKAnnotationView)mapView.DequeueReusableAnnotation(useId);
if (pinView == null)
pinView = new MKAnnotationView(annotation, useId);
if (!annotation.IsCluster)
{
pinView.CanShowCallout = true;
double testWidth = value.Length < 11 ? 65 : 90;
var button = new UIButton(new CGRect(testWidth, 5, 10, 20));
button.SetImage(UIImage.FromBundle("disclosure"), UIControlState.Normal);
JSBadgeView badge = new JSBadgeView(button, JSBadgeView.Alignment.CenterLeft)
{
BadgeBackgroundColor = color,
BadgeStrokeColor = UIColor.Red,
BadgeTextColor = Color.FromHex(ColorConstants.DarkGreyDetailText).ToUIColor(),
BadgeTextFont = UIFont.FromName("AvenirNext-Regular", 11),
BadgeAlignment = JSBadgeView.Alignment.CenterLeft,
BadgeText = value
};
UIView view = new UIView(new CGRect(0, 0, testWidth + 10, 30));
view.ClipsToBounds = false;
view.AddSubview(button);
pinView.RightCalloutAccessoryView = view;
if (string.IsNullOrEmpty(imageURL))
{
var imageView = new UIImageView(new CGRect(0, 0, 42, 42));
imageView.Image = UIImage.FromBundle("notavailable");
imageView.ContentMode = UIViewContentMode.ScaleAspectFit;
pinView.LeftCalloutAccessoryView = imageView;
}
else
{
FromUrl(imageURL, pinView);
}
}
pinView.Image = UIImage.FromBundle((string.IsNullOrEmpty(imageName)) ? "flowgreenpin" : imageName);
if (annotation.IsCluster)
{
pinView.CanShowCallout = false;
JSBadgeView badge = new JSBadgeView(pinView, JSBadgeView.Alignment.TopCenter)
{
BadgeBackgroundColor = UIColor.FromRGB(0.451f, 0.847f, 0.988f),
BadgeStrokeColor = UIColor.Red,
BadgeTextColor = UIColor.White,
BadgeTextFont = UIFont.FromName("AvenirNext-Regular", 11),
BadgeAlignment = JSBadgeView.Alignment.TopCenter,
BadgeText = annotation.Annotations.Count.ToString()
};
}
return pinView;
}
public static void InvokedOnMainThread(Action Action)
{
if (NSThread.Current.IsMainThread)
Action();
else
Invoker.BeginInvokeOnMainThread(() => Action());
}
static async Task FromUrl(string uri, MKAnnotationView pinView)
{
using (var httpClient = new HttpClient())
{
Task<byte[]> contentsTask = httpClient.GetByteArrayAsync(uri);
// await! control returns to the caller and the task continues to run on another thread
var contents = await contentsTask;
// load from bytes
var image = UIImage.LoadFromData(NSData.FromArray(contents));
var imageView = new UIImageView(new CGRect(0, 0, 42, 42));
imageView.Image = image;
imageView.ContentMode = UIViewContentMode.ScaleAspectFit;
InvokedOnMainThread(delegate
{
pinView.LeftCalloutAccessoryView = imageView;
});
}
}
public override void DidSelectAnnotationView(MKMapView mapView, MKAnnotationView view)
{
var annotation = ObjCRuntime.Runtime.GetNSObject(view.Annotation.Handle) as CCHMapClusterAnnotation;
if (annotation != null)
{
if (!annotation.IsCluster)
{
UITapGestureRecognizer tap = new UITapGestureRecognizer(OnTap);
view.AddGestureRecognizer(tap);
return;
}
MKMapRect mapRect = annotation.MapRect;
UIEdgeInsets edgeInsets = new UIEdgeInsets(20, 20, 20, 20);
mapView.SetVisibleMapRect(mapRect, edgeInsets, true);
}
mapView.DeselectAnnotation(view.Annotation, true);
}
public override void DidDeselectAnnotationView(MKMapView mapView, MKAnnotationView view)
{
view.GestureRecognizers = null;
}
public override void CalloutAccessoryControlTapped(MKMapView mapView, MKAnnotationView view, UIControl control)
{
if (view != null)
{
var clusterPin = ObjCRuntime.Runtime.GetNSObject(view.Annotation.Handle) as CCHMapClusterAnnotation;
var location = Locations.Where(l => (l.City + " " + l.ExternalReference) == clusterPin.Subtitle).ToList();
if (location != null && location.Count != 0)
{
customMap.ClickedCallout(location.First());
}
}
}
private void OnTap(UIGestureRecognizer gesture)
{
var pinView = gesture.View as MKAnnotationView;
if (pinView != null)
{
var clusterPin = ObjCRuntime.Runtime.GetNSObject(pinView.Annotation.Handle) as CCHMapClusterAnnotation;
var location = Locations.Where(l => (l.City + " " + l.ExternalReference) == clusterPin.Subtitle).ToList();
if (location != null && location.Count != 0)
{
customMap.ClickedCallout(location.First());
}
}
}
public override MKOverlayRenderer OverlayRenderer(MKMapView mapView, IMKOverlay overlay)
{
var osmOverlay = overlay as WMSTileOverlay;
if (osmOverlay != null)
{
return new MKTileOverlayRenderer(new WMSTileOverlay(osmOverlay.BaseUrl, osmOverlay.Layer) { CanReplaceMapContent = false });
}
return new MKTileOverlayRenderer(new WMSProvincieTileOverlay() { CanReplaceMapContent = false });
}
}
internal class CCHMapDelegate : UIViewController, ICCHMapClusterControllerDelegate//CCHMapClusterControllerDelegate
{
[Export("mapClusterController:titleForMapClusterAnnotation:")]
public string TitleForMapClusterAnnotation(CCHMapClusterController mapClusterController, CCHMapClusterAnnotation mapClusterAnnotation)
{
var annotationsCount = mapClusterAnnotation.Annotations.Count;
if (annotationsCount != 1) return "";
MKPointAnnotation annot = (MKPointAnnotation)mapClusterAnnotation.Annotations.First();
return annot.Title;
}
//public override string MapClusterTitleForAnnotation (CCHMapClusterController mapClusterController, CCHMapClusterAnnotation mapClusterAnnotation)
//{
// if (mapClusterAnnotation.Annotations.Count == 1) {
// MKPointAnnotation annot = (MKPointAnnotation)mapClusterAnnotation.Annotations.First ();
// return annot.Title;
// }
// return "";
//}
[Export("mapClusterController:subtitleForMapClusterAnnotation:")]
public string SubtitleForMapClusterAnnotation(CCHMapClusterController mapClusterController, CCHMapClusterAnnotation mapClusterAnnotation)
{
if (mapClusterAnnotation.Annotations.Count != 1) return "";
MKPointAnnotation annot = (MKPointAnnotation)mapClusterAnnotation.Annotations.First();
return annot.Subtitle;
}
//public override string MapClusterSubtitleForAnnotation (CCHMapClusterController mapClusterController, CCHMapClusterAnnotation mapClusterAnnotation)
//{
// if (mapClusterAnnotation.Annotations.Count == 1) {
// MKPointAnnotation annot = (MKPointAnnotation)mapClusterAnnotation.Annotations.First ();
// return annot.Subtitle;
// }
// return "";
//}
[Export("mapClusterController:willReuseMapClusterAnnotation:")]
public void WillReuseMapClusterAnnotation(CCHMapClusterController mapClusterController, CCHMapClusterAnnotation mapClusterAnnotation)
{
}
//public override void MapClusterWillReuseAnnotation (CCHMapClusterController mapClusterController, CCHMapClusterAnnotation mapClusterAnnotation)
//{
//}
}
}
...

ASP.NET MVC validation return lowercase property name

In my ASP.NET MVC Core web application the Json serialization of properties is set to camel case (with first letter lowercase):
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
.AddJsonOptions(opt =>
{
opt.SerializerSettings.ContractResolver = new DefaultContractResolver { NamingStrategy = new CamelCaseNamingStrategy() };
opt.SerializerSettings.Converters.Add(new StringEnumConverter(true));
});
The serialization to the client is working as expected.
But when the javascript client tries to post data and this data is not valid, he receives a validation message with capital letter properties, this validation messages are the ModelState:
{"Info":["The Info field is required."]}
Is there a way to make ASP.NET return lowercase property in validation messages of the ModelState to reflect the naming strategy?
The solution is to disable the automatic api validation filter and create own json result with the validation messages:
services.Configure<ApiBehaviorOptions>(options =>
{
options.SuppressModelStateInvalidFilter = true;
});
And in the controller:
protected ActionResult ValidationFailed()
{
var errorList = ModelState.ToDictionary(
kvp => kvp.Key.ToCamelCase(),
kvp => kvp.Value.Errors.Select(e => e.ErrorMessage).ToArray()
);
return BadRequest(errorList);
}
public async Task<ActionResult> Create([FromBody]TCreateDto model)
{
if (ModelState.IsValid == false)
{
return ValidationFailed();
}
...
}
The string helper method:
public static string ToCamelCase(this string name)
{
if (string.IsNullOrEmpty(name))
{
return name;
}
return name.Substring(0, 1).ToLower() + name.Substring(1);
}
There is an easier solution. Use Fluent Validator's ValidatorOptions.Global.PropertyNameResolver. Taken from here and converted to C# 8 and Fluent Validation 9:
In Startup.cs, ConfigureServices use:
services
.AddControllers()
.SetCompatibilityVersion(CompatibilityVersion.Version_3_0)
.AddFluentValidation(fv =>
{
fv.RegisterValidatorsFromAssemblyContaining<MyValidator>();
// Convert property names to camelCase as Asp.Net Core does https://github.com/FluentValidation/FluentValidation/issues/226
ValidatorOptions.Global.PropertyNameResolver = CamelCasePropertyNameResolver.ResolvePropertyName;
})
.AddNewtonsoftJson(NewtonsoftUtils.SetupNewtonsoftOptionsDefaults);
and resolver itself:
/// <summary>
/// Convert property names to camelCase as Asp.Net Core does
/// https://github.com/FluentValidation/FluentValidation/issues/226
/// </summary>
public class CamelCasePropertyNameResolver
{
public static string? ResolvePropertyName(Type type, MemberInfo memberInfo, LambdaExpression expression)
{
return ToCamelCase(DefaultPropertyNameResolver(type, memberInfo, expression));
}
private static string? DefaultPropertyNameResolver(Type type, MemberInfo memberInfo, LambdaExpression expression)
{
if (expression != null)
{
var chain = PropertyChain.FromExpression(expression);
if (chain.Count > 0)
{
return chain.ToString();
}
}
if (memberInfo != null)
{
return memberInfo.Name;
}
return null;
}
private static string? ToCamelCase(string? s)
{
if (string.IsNullOrEmpty(s) || !char.IsUpper(s[0]))
{
return s;
}
var chars = s.ToCharArray();
for (var i = 0; i < chars.Length; i++)
{
if (i == 1 && !char.IsUpper(chars[i]))
{
break;
}
var hasNext = (i + 1 < chars.Length);
if (i > 0 && hasNext && !char.IsUpper(chars[i + 1]))
{
break;
}
chars[i] = char.ToLower(chars[i], CultureInfo.InvariantCulture);
}
return new string(chars);
}
}
I have faced the same issue. I have overridden DefaultProblemDetailsFactory.cs from the source code and add logic to change the first letters in the 'errors' dictionary.
Steps:
1 - Create new CustomProblemDetailsFactory.cs class:
internal sealed class CustomProblemDetailsFactory : ProblemDetailsFactory
{
private readonly ApiBehaviorOptions _options;
public CustomProblemDetailsFactory(IOptions<ApiBehaviorOptions> options)
{
_options = options?.Value ?? throw new ArgumentNullException(nameof(options));
}
public override ProblemDetails CreateProblemDetails(
HttpContext httpContext,
int? statusCode = null,
string? title = null,
string? type = null,
string? detail = null,
string? instance = null)
{
statusCode ??= 500;
var problemDetails = new ProblemDetails
{
Status = statusCode,
Title = title,
Type = type,
Detail = detail,
Instance = instance,
};
ApplyProblemDetailsDefaults(httpContext, problemDetails, statusCode.Value);
return problemDetails;
}
public override ValidationProblemDetails CreateValidationProblemDetails(
HttpContext httpContext,
ModelStateDictionary modelStateDictionary,
int? statusCode = null,
string? title = null,
string? type = null,
string? detail = null,
string? instance = null)
{
if (modelStateDictionary == null)
{
throw new ArgumentNullException(nameof(modelStateDictionary));
}
statusCode ??= 400;
var problemDetails = new ValidationProblemDetails(modelStateDictionary)
{
Status = statusCode,
Type = type,
Detail = detail,
Instance = instance,
};
if (title != null)
{
// For validation problem details, don't overwrite the default title with null.
problemDetails.Title = title;
}
// FIX LOWERCASE, MAKE THE FIRST LETTERS LOWERCASE
///-----------------------------
if (problemDetails.Errors != null)
{
var newErrors = problemDetails.Errors.ToDictionary(x => this.MakeFirstLetterLowercase(x.Key), x => x.Value);
problemDetails.Errors.Clear();
foreach (var keyValue in newErrors)
{
problemDetails.Errors.Add(keyValue.Key, keyValue.Value);
}
}
///-----------------------------
ApplyProblemDetailsDefaults(httpContext, problemDetails, statusCode.Value);
return problemDetails;
}
private void ApplyProblemDetailsDefaults(HttpContext httpContext, ProblemDetails problemDetails, int statusCode)
{
problemDetails.Status ??= statusCode;
if (_options.ClientErrorMapping.TryGetValue(statusCode, out var clientErrorData))
{
problemDetails.Title ??= clientErrorData.Title;
problemDetails.Type ??= clientErrorData.Link;
}
var traceId = Activity.Current?.Id ?? httpContext?.TraceIdentifier;
if (traceId != null)
{
problemDetails.Extensions["traceId"] = traceId;
}
}
private string MakeFirstLetterLowercase(string str)
{
if (!string.IsNullOrEmpty(str) && char.IsUpper(str[0]))
{
return str.Length == 1 ? char.ToLower(str[0]).ToString() : char.ToLower(str[0]) + str[1..];
}
return str;
}
}
2 - In the Startup.cs override the default ProblemDetailsFactory:
services.AddSingleton<ProblemDetailsFactory, CustomProblemDetailsFactory>();
After that all keys in the dictionary 'errors' will start with lowercase

ActionFilter to read Contents before RedirectToAction

I wish to record deletes and edits, and thought the best way would be to apply An actionFilter
Attribute to my delete and edit [ post ] methods
But because the end results is a redirect to action, my Context.Result is always null
because there is only a Context.RedirectToAction results available.
Now before i go creating some code to plug into my delete and Edit functions, has anyone tried something like this!, and could you possibly advise?
Thanks
Action Code:
[HttpPost, ValidateInput(false)]
[SiteChangeLogger(LogType = "Update", TableName = "Affiliates")]
public ActionResult Edit(Affiliate affiliate, FormCollection form)
{
var existing = db2.Affiliates.SingleOrDefault(x => x.AffiliateId == affiliate.AffiliateId);
ViewBag.before = Common.Strings.Base64Encode(Common.Strings.ToJsonString(existing));
if (ModelState.IsValid)
{
try
{
var curFiles = new NameValueCollection();
curFiles["AffiliateLogo"] = affiliate.AffiliateLogo;
if (!String.IsNullOrWhiteSpace(form["AffiliateLogo"]))
{
UploadFiles(form,curFiles);
TryUpdateModel(affiliate, form);
var oldFileName = affiliate.AffiliateLogo;
var newFileName = Common.Strings.RandomFileName();
new WebImage(Server.MapPath("~/Content/images/" + affiliate.AffiliateLogo))
.Resize(200, 50, true, true)
.Crop(1, 1)
.Save(Server.MapPath("~/Content/images/" + newFileName), "png", true);
affiliate.AffiliateLogo = newFileName + ".png";
Common.Common.TryAndDeleteFile("~/Content/images/" + oldFileName);
}
else
{
affiliate.AffiliateLogo = existing.AffiliateLogo;
}
}
catch (Exception ex)
{
Common.Common.CompileErrorMessage(ex,"ADMIN.Affiliate.Edit");
}
finally
{
db.Entry(affiliate).State = EntityState.Modified;
db.SaveChanges();
}
ViewBag.after = Common.Strings.Base64Encode(Common.Strings.ToJsonString(affiliate));
return RedirectToAction("Index");
}
return View(affiliate);
}
my Filter Code
public override void OnResultExecuted(ResultExecutedContext fc)
{
var viewResult = fc.Result as ViewResult;
if(viewResult == null) return;
var beforeData = viewResult.ViewBag.before;
var afterData = viewResult.ViewBag.after;
if (beforeData == null && afterData == null) return;
var ctx = new SgeGamesContext();
var eventId = 0;
var siteChangeLogEvent = ctx.SiteChangeLogEvents.SingleOrDefault(x => x.SiteChangeLogEventName == LogType);
if (siteChangeLogEvent != null)
{
eventId = siteChangeLogEvent.SiteChangeLogEventId;
}
var model = new Sge.Games.Data.Models.SiteChangeLog
{
SiteChangeLogTable = TableName,
SiteId = 1,
SiteChangeLogAfterContent = afterData,
SiteChangeLogBeforeContent = beforeData,
SiteChangeLogEventId = eventId
};
ctx.SiteChangeLogs.Add(model);
ctx.SaveChanges();
base.OnResultExecuted(fc);
}
You could access the ViewBag directly, you don't need a ViewResult:
public override void OnResultExecuted(ResultExecutedContext fc)
{
var before = fc.Controller.ViewBag.before;
var after = fc.Controller.ViewBag.after;
...
}
Also you probably want to use the OnActionExecuted event instead of OnResultExecuted.

make in the URL the controllername visible but not the parameters

Is there a way to create an URL with only the name of the controller but not its parameters in MVC3
I do an #url.Action("action","controller",the model) an I want that the user see;
'/controller/action' not '/controller/action?...&..&..'
I have no idea how i have to do this.
You can use MVC contrlib. I did something similar without the need for contrlib
public static class UrlExtensions
{
public static string Action<TController>(this UrlHelper urlHelper, Expression<Action<TController>> expression) where TController : Controller
{
return BuildUrlFromExpression(urlHelper.RequestContext, urlHelper.RouteCollection, expression);
}
public static string ActionWithParameters<TController>(this UrlHelper urlHelper, Expression<Action<TController>> expression) where TController : Controller
{
return BuildUrlFromExpressionWithParameters(urlHelper.RequestContext, urlHelper.RouteCollection, expression);
}
public static RedirectToRouteResult Redirect<TController>(this TController controller, Expression<Action<TController>> expression) where TController : Controller
{
var valuesFromExpression = ExpressionHelper.GetRouteValuesFromExpressionWithParameters(expression);
return new RedirectToRouteResult(valuesFromExpression);
}
private static string BuildUrlFromExpression<TController>(RequestContext context, RouteCollection routeCollection, Expression<Action<TController>> action) where TController : Controller
{
var valuesFromExpression = ExpressionHelper.GetRouteValuesFromExpression(action);
var virtualPathForArea = RouteCollectionExtensions.GetVirtualPathForArea(routeCollection, context, valuesFromExpression);
if (virtualPathForArea != null)
return virtualPathForArea.VirtualPath;
return null;
}
private static string BuildUrlFromExpressionWithParameters<TController>(RequestContext context, RouteCollection routeCollection, Expression<Action<TController>> action) where TController : Controller
{
var valuesFromExpression = ExpressionHelper.GetRouteValuesFromExpressionWithParameters(action);
var virtualPathForArea = RouteCollectionExtensions.GetVirtualPathForArea(routeCollection, context, valuesFromExpression);
if (virtualPathForArea != null)
return virtualPathForArea.VirtualPath;
return null;
}
}
public static class ExpressionHelper
{
public static RouteValueDictionary GetRouteValuesFromExpression<TController>(Expression<Action<TController>> action) where TController : Controller
{
MethodCallExpression call;
return GetRouteValuesFromExpression(action, out call);
}
public static RouteValueDictionary GetRouteValuesFromExpressionWithParameters<TController>(Expression<Action<TController>> action) where TController : Controller
{
MethodCallExpression call;
var rvd = GetRouteValuesFromExpression(action, out call);
AddParameterValuesFromExpressionToDictionary(rvd, call);
return rvd;
}
private static RouteValueDictionary GetRouteValuesFromExpression<TController>(Expression<Action<TController>> action, out MethodCallExpression call) where TController : Controller
{
if (action == null)
throw new ArgumentNullException("action");
call = action.Body as MethodCallExpression;
if (call == null)
throw new ArgumentException("MustBeMethodCall", "action");
string name = typeof(TController).Name;
if (!name.EndsWith("Controller", StringComparison.OrdinalIgnoreCase))
throw new ArgumentException("TargetMustEndInController", "action");
string str = name.Substring(0, name.Length - "Controller".Length);
if (str.Length == 0)
throw new ArgumentException("CannotRouteToController", "action");
string targetActionName = GetTargetActionName(call.Method);
var rvd = new RouteValueDictionary();
rvd.Add("Controller", (object)str);
rvd.Add("Action", (object)targetActionName);
var linkAreaAttribute = typeof(TController).GetCustomAttributes(typeof(ActionLinkAreaAttribute), true).FirstOrDefault() as ActionLinkAreaAttribute;
if (linkAreaAttribute != null)
{
string area = linkAreaAttribute.Area;
rvd.Add("Area", (object)area);
}
return rvd;
}
public static string GetInputName<TModel, TProperty>(Expression<Func<TModel, TProperty>> expression)
{
if (expression.Body.NodeType == ExpressionType.Call)
return GetInputName((MethodCallExpression)expression.Body).Substring(expression.Parameters[0].Name.Length + 1);
else
return expression.Body.ToString().Substring(expression.Parameters[0].Name.Length + 1);
}
public static PropertyInfo GetPropertyInfo<TModel, TValue>(Expression<Func<TModel, TValue>> expression)
{
var member = expression.Body as MemberExpression;
if (member == null)
return null;
var propInfo = member.Member as PropertyInfo;
return propInfo;
}
private static string GetInputName(MethodCallExpression expression)
{
var expression1 = expression.Object as MethodCallExpression;
if (expression1 != null)
return GetInputName(expression1);
else
return expression.Object.ToString();
}
private static string GetTargetActionName(MethodInfo methodInfo)
{
if (methodInfo == null) throw new ArgumentNullException("methodInfo");
var name = methodInfo.Name;
if (methodInfo.IsDefined(typeof (NonActionAttribute), true))
{
throw new InvalidOperationException(string.Format(Helpers.MyFormat, "CannotCallNonAction {0}", name));
}
var actionNameAttribute = methodInfo.GetCustomAttributes(typeof (ActionNameAttribute), true).OfType<ActionNameAttribute>().FirstOrDefault();
if (actionNameAttribute != null)
return actionNameAttribute.Name;
if (methodInfo.DeclaringType.IsSubclassOf(typeof (AsyncController)))
{
if (name.EndsWith("Async", StringComparison.OrdinalIgnoreCase))
return name.Substring(0, name.Length - "Async".Length);
if (name.EndsWith("Completed", StringComparison.OrdinalIgnoreCase))
throw new InvalidOperationException(string.Format(Helpers.MyFormat, "CannotCallCompletedMethod: {0}", name));
}
return name;
}
private static void AddParameterValuesFromExpressionToDictionary(RouteValueDictionary rvd, MethodCallExpression call)
{
var parameters = call.Method.GetParameters();
if (parameters.Length <= 0)
return;
for (int index = 0; index < parameters.Length; ++index)
{
var expression = call.Arguments[index];
var constantExpression = expression as ConstantExpression;
var obj = constantExpression == null ? CachedExpressionCompiler.Evaluate(expression) : constantExpression.Value;
rvd.Add(parameters[index].Name, obj);
}
}
}
From your view you can now do, the default values has to be passed for the LINQ expression to work, but they wil not be rendered
#(Url.Action<MyController>(x => x.MethodName(null, 0, 0)))

Resources