WP7 OData Problem with URLs that contain characters that are invalid in cookie paths

Topics: OData Library
Oct 8, 2012 at 9:25 AM

Hi, I've ran into a problem while accessing OData service (non-WCF) using the OData client library for Windows Phone 7. We have a custom-built authentication solution on top of the service and it uses Cookies (handled in DataServiceContext.SendingRequest and .ReadingResponse).

When I get a list of items, all works fine. However, when then querying for details of a single entry, I get a "System.InvalidOperationException] {"An error occurred while processing this request."}". The inner exception is "System.Net.CookieException: {"The 'Path'='/mydataservice/y_get_task_list_3Collection(key1='00011342',key2='4408000620',user_id='')' part of the cookie is invalid."}".

The query is made using the context like this:

var query = from item in context.task_collection
			where item.key1 == param1 && item.key2 == param2 && item.user_id == ""
			select item;
itemDetails.LoadAsync(query);

According to the message the Path contains illegal characters - which is actually true, since comma might be an illegal character in the Path part [1]. However, the commas are caused by the use of a compound key on the data service side. Is there something we're doing wrong here or is this just a known issue/limitation with the client library?

[1] http://stackoverflow.com/a/1969339

Exception:

{"An error occurred while processing this request."}
    [System.InvalidOperationException]: {"An error occurred while processing this request."}
    _data: {System.Collections.ListDictionaryInternal}
    _HResult: -2146233079
    _innerException: {"The 'Path'='/mydataservice/task_collection(key1='00011342',key2='4408000620',user_id='')' part of the cookie is invalid."}
    _message: "An error occurred while processing this request."
    _methodDescs: {System.IntPtr[18]}
    _optionalData: null
    Data: {System.Collections.ListDictionaryInternal}
    HResult: -2146233079
    InnerException: {"The 'Path'='/mydataservice/task_collection(key1='00011342',key2='4408000620',user_id='')' part of the cookie is invalid."}
    Message: "An error occurred while processing this request."
    StackTrace: "   at System.Data.Services.Client.BaseAsyncResult.EndExecute[T](Object source, String method, IAsyncResult asyncResult)\r\n   at System.Data.Services.Client.QueryResult.EndExecute[TElement](Object source, IAsyncResult asyncResult)\r\n   at System.Data.Services.Client.DataServiceRequest.EndExecute[TElement](Object source, DataServiceContext context, IAsyncResult asyncResult)\r\n   at System.Data.Services.Client.DataServiceQuery`1.EndExecute(IAsyncResult asyncResult)\r\n   at System.Data.Services.Client.DataServiceCollection`1.<>c__DisplayClass2.b__1(IAsyncResult asyncResult)\r\n   at System.Data.Services.Client.DataServiceCollection`1.<>c__DisplayClass11.<>c__DisplayClass13.b__f()\r\n   at System.Reflection.RuntimeMethodInfo.InternalInvoke(RuntimeMethodInfo rtmi, Object obj, BindingFlags invokeAttr, Binder binder, Object parameters, CultureInfo culture, Boolean isBinderDefault, Assembly caller, Boolean verifyAccess, StackCrawlMark& stackMark)\r\n   at System.	

Inner Exception:

args.Error.InnerException
{"The 'Path'='/mydataservice/task_collection(key1='00011342',key2='4408000620',user_id='')' part of the cookie is invalid."}
    [System.Net.CookieException]: {"The 'Path'='/mydataservice/task_collection(key1='00011342',key2='4408000620',user_id='')' part of the cookie is invalid."}
    _data: {System.Collections.ListDictionaryInternal}
    _HResult: -2146233033
    _innerException: null
    _message: "The 'Path'='/mydataservice/task_collection(key1='00011342',key2='4408000620',user_id='')' part of the cookie is invalid."
    _methodDescs: {System.IntPtr[65]}
    _optionalData: null
    Data: {System.Collections.ListDictionaryInternal}
    HResult: -2146233033
    InnerException: Could not evaluate expression
    Message: "The 'Path'='/mydataservice/task_collection(key1='00011342',key2='4408000620',user_id='')' part of the cookie is invalid."
    StackTrace: 
	   at System.Net.Cookie.VerifySetDefaults(CookieVariant variant, Uri uri, Boolean isLocalDomain, String localDomain, Boolean set_default, Boolean isThrow)
	   at System.Net.CookieContainer.Add(Uri uri, CookieCollection cookies)
	   at System.Net.Browser.HttpWebRequestHelper.GetCookieHeader(CookieContainer publicContainer, Uri requestUri)
	   at System.Net.Browser.ClientHttpWebRequest.PrepareAndSendRequest(String method, Uri requestUri, Stream requestBodyStream, WebHeaderCollection headerCollection, CookieContainer cookieContainer)
	   at System.Net.Browser.ClientHttpWebRequest.BeginGetResponseImplementation()
	   at System.Net.Browser.ClientHttpWebRequest.InternalBeginGetResponse(AsyncCallback callback, Object state)
	   at System.Net.Browser.ClientHttpWebRequest.BeginGetResponse(AsyncCallback callback, Object state)
	   at System.Data.Services.Http.ClientHttpWebRequest.BeginGetResponse(AsyncCallback callback, Object state)
	   at System.Data.Services.Client.BaseAsyncResult.InvokeAsync(Func`3 asyncAction, AsyncCallback callback, Object state)
	   at System.Data.Services.Client.QueryResult.BeginExecute(DataServiceContext context)
	   at System.Data.Services.Client.DataServiceRequest.BeginExecute(Object source, DataServiceContext context, AsyncCallback callback, Object state)
	   at System.Data.Services.Client.DataServiceQuery`1.BeginExecute(AsyncCallback callback, Object state)
	   at System.Data.Services.Client.DataServiceCollection`1.<>c__DisplayClass2.b__0(AsyncCallback asyncCallback)
	   at System.Data.Services.Client.DataServiceCollection`1.BeginLoadAsyncOperation(Func`2 beginCall, Func`2 endCall)
	   at System.Data.Services.Client.DataServiceCollection`1.LoadAsync(IQueryable`1 query)
	   at MobileApprovalTool.Services.TravelInfoService.GetTripDetailsAsync(String tripNumber, String personNumber)
	   at MobileApprovalTool.ViewModels.MainViewModel.LoadTripDetails()
	   at MobileApprovalTool.Views.AllViewPage.listTravel_SelectionChanged(Object sender, SelectionChangedEventArgs e)
	   at System.Windows.Controls.Primitives.Selector.OnSelectionChanged(SelectionChangedEventArgs e)
	   at System.Windows.Controls.Primitives.Selector.InvokeSelectionChanged(List`1 unselectedItems, List`1 selectedItems)
	   at System.Windows.Controls.Primitives.Selector.SelectionChanger.End()
	   at System.Windows.Controls.Primitives.Selector.SelectionChanger.SelectJustThisItem(Object o)
	   at System.Windows.Controls.Primitives.Selector.OnSelectedItemChanged(Object oldValue, Object newValue)
	   at System.Windows.Controls.Primitives.Selector.OnSelectedItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
	   at System.Windows.DependencyObject.RaisePropertyChangeNotifications(DependencyProperty dp, Object oldValue, Object newValue)
	   at System.Windows.DependencyObject.UpdateEffectiveValue(DependencyProperty property, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, ValueOperation operation)
	   at System.Windows.DependencyObject.RefreshExpression(DependencyProperty dp)
	   at System.Windows.Data.BindingExpression.RefreshExpression()
	   at System.Windows.Data.BindingExpression.SendDataToTarget()
	   at System.Windows.Data.BindingExpression.SourcePropertyChanged(PropertyPathListener sender, PropertyPathChangedEventArgs args)
	   at System.Windows.PropertyPathListener.RaisePropertyPathStepChanged(PropertyPathStep source)
	   at System.Windows.PropertyAccessPathStep.RaisePropertyPathStepChanged(PropertyListener source)
	   at System.Windows.CLRPropertyListener.SourcePropertyChanged(Object sender, PropertyChangedEventArgs args)
	   at System.Windows.Data.WeakPropertyChangedListener.PropertyChangedCallback(Object sender, PropertyChangedEventArgs args)
	   at GalaSoft.MvvmLight.ObservableObject.RaisePropertyChanged(String propertyName)
	   at Tools.ViewModelBase.NotifyPropertyChanged(String propertyName)
	   at MobileApprovalTool.ViewModels.MainViewModel.set_SelectedLightItem(ApprovableItem value)
	   at System.Reflection.RuntimeMethodInfo.InternalInvoke(RuntimeMethodInfo rtmi, Object obj, BindingFlags invokeAttr, Binder binder, Object parameters, CultureInfo culture, Boolean isBinderDefault, Assembly caller, Boolean verifyAccess, StackCrawlMark& stackMark)
	   at System.Reflection.RuntimeMethodInfo.InternalInvoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, StackCrawlMark& stackMark)
	   at System.Reflection.RuntimePropertyInfo.InternalSetValue(PropertyInfo thisProperty, Object obj, Object value, Object[] index, StackCrawlMark& stackMark)
	   at System.Reflection.RuntimePropertyInfo.SetValue(Object obj, Object value, Object[] index)
	   at System.Windows.CLRPropertyListener.set_Value(Object value)
	   at System.Windows.PropertyAccessPathStep.set_Value(Object value)
	   at System.Windows.PropertyPathListener.set_LeafValue(Object value)
	   at System.Windows.Data.BindingExpression.UpdateValue()
	   at System.Windows.Data.BindingExpression.UpdateValueIfNecessary()
	   at System.Windows.Data.BindingExpression.TargetPropertyChanged(DependencyObject sender, DependencyProperty dp)
	   at System.Windows.DependencyObject.OnPropertyChanged(DependencyProperty dp)
	   at System.Windows.FrameworkElement.OnPropertyChanged(DependencyProperty dp)
	   at System.Windows.Controls.Primitives.Selector.OnPropertyChanged(DependencyProperty dp)
	   at System.Windows.DependencyObject.RaisePropertyChangeNotifications(DependencyProperty dp, Object oldValue, Object newValue)
	   at System.Windows.DependencyObject.UpdateEffectiveValue(DependencyProperty property, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, ValueOperation operation)
	   at System.Windows.DependencyObject.SetValueInternal(DependencyProperty dp, Object value, Boolean allowReadOnlySet)
	   at System.Windows.DependencyObject.SetValueInternal(DependencyProperty dp, Object value)
	   at System.Windows.DependencyObject.SetValue(DependencyProperty dp, Object value)
	   at System.Windows.Controls.Primitives.Selector.set_SelectedItem(Object value)
	   at System.Windows.Controls.Primitives.Selector.UpdatePublicSelectionProperties(Int32 oldSelectedIndex, Int32 newSelectedIndex, Object oldSelectedItem, Object newSelectedItem)
	   at System.Windows.Controls.Primitives.Selector.SelectionChanger.End()
	   at System.Windows.Controls.Primitives.Selector.SelectionChanger.SelectJustThisItem(Int32 oldIndex, Int32 newIndex)
	   at System.Windows.Controls.ListBox.MakeSingleSelection(Int32 index)
	   at System.Windows.Controls.ListBox.HandleItemSelection(ListBoxItem item, Boolean isMouseSelection)
	   at System.Windows.Controls.ListBox.OnListBoxItemClicked(ListBoxItem item)
	   at System.Windows.Controls.ListBoxItem.OnManipulationCompleted(ManipulationCompletedEventArgs e)
	   at System.Windows.Controls.Control.OnManipulationCompleted(Control ctrl, EventArgs e)
	   at MS.Internal.JoltHelper.FireEvent(IntPtr unmanagedObj, IntPtr unmanagedObjArgs, Int32 argsTypeIndex, Int32 actualArgsTypeIndex, String eventName)
Oct 9, 2012 at 6:30 PM

Hi,

This seems to be a problem at system.net level as the exception and not the phone client level. The request doesn't reach the phone client as the system.net throws the cookie exception. You may need to look into escaping on your layer so that you can get pass system.net. The windows phone client doesn't any special handling for cookies.

Thanks,

Turker

Oct 10, 2012 at 8:38 AM

Hi,

I think this isn't solely the problem of System.Net core library. I made to reproduce it with constructing similar CookieContainer and CookieCollection directly and it works fine. I think this is related to the way we are adding cookies to HTTP headers using the DataServiceContext.SendingRequest event. We're now looking into forking this codebase (luckily it's open source :)) to provide access to the CookieContainer of the ClientHttpWebRequest when it is being sent (similar to the SendingRequest event).

-Henri