publicvoidNavigate(){// Browse the vault from the root.stringuserChoice="";stringcurrentPath="";while(userChoice!=null){// Construct the path.// This will result in '/v1/v2/' format.// Root path will be represented with just '/'.currentPath+=userChoice+"/";userChoice=PromptView(currentPath);}}publicstringPromptView(stringpath){// Get view contents.varcontents=GetViewContents(path);// Display objectsvarobjects=contents.Items.Select(i=>i.ObjectVersion).Where(i=>i!=null).ToList();// List objectsConsole.WriteLine("Objects in this view:");foreach(ObjectVersionoinobjects)Console.WriteLine(o.Title);Console.WriteLine();// We'll gather all possible navigation targets in one list.List<object>navigableItems=newList<object>();// List viewsvarviews=contents.Items.Select(i=>i.View).Where(i=>i!=null).ToList();Console.WriteLine("Other views in this view:");foreach(Viewvinviews){// Add the view to the list as a possible navigation target.// Also prefix the view name with its index in the list.navigableItems.Add(v);Console.WriteLine("{0}: {1}",navigableItems.Count,v.Name);}Console.WriteLine();// Display property folders.varpropertyFolders=contents.Items.Select(i=>i.PropertyFolder).Where(i=>i!=null).ToList();Console.WriteLine("Property folders in this view:");foreach(TypedValuepinpropertyFolders){// Add the property folder to the list as a possible navigation target.// Also prefix the view name with its index in the list.navigableItems.Add(p);Console.WriteLine("{0}: {1}",navigableItems.Count,p.DisplayValue);}Console.WriteLine();// Read the user input for the next view.objectnextItem;while(true){Console.WriteLine("Select the next directory or type 'q' to exit:");stringinput=Console.ReadLine();// 'q' stop the navigation.if(input=="q")returnnull;// Parse the string input.intindex;if(!int.TryParse(input,outindex)){Console.WriteLine("Invalid input!");Console.WriteLine();continue;}// Make sure the string is within the valid range.if(index<1||index>navigableItems.Count){Console.WriteLine("Input out of range!");Console.WriteLine();continue;}// Input was okay so we can select the next item.nextItem=navigableItems[index-1];break;}// Depending on the item type, construct the view path differently.// For views we need to prefix the ID with a 'v'.if(nextItemisView)return"v"+((View)nextItem).ID;// For property folders we need to decide on the prefix based on datatype// and after this we can use the SerializedValue from the TypedValue.if(nextItemisTypedValue){stringprefix;TypedValuetv=((TypedValue)nextItem);switch(tv.DataType){caseMFDataType.Lookup:prefix="l";break;caseMFDataType.MultiLineText:prefix="s";break;caseMFDataType.Text:prefix="t";break;default:thrownewNotImplementedException();}returnprefix+tv.SerializedValue;}returnnull;}publicFolderContentItemsGetViewContents(stringpath){// Construct the URL by filling path.// Note that the input path in our case is in "/foo/bar/" format.stringurl="http://example.org/REST/views"+path+"items";// Create the web request.WebRequestrequest=WebRequest.Create(url);// Fill the authentication information.request.Headers["X-Authentication"]=this.AuthenticationToken;// Get the response.varresponse=request.GetResponse();// Use JSON serializer to deserialize the FolderContentItems from the response.varserializer=newDataContractJsonSerializer(typeof(FolderContentItems));varitems=(FolderContentItems)serializer.ReadObject(response.GetResponseStream());returnitems;}