Linq OData REST API to Query a SharePoint List - vb.net

Hey all I am new at using linq and found a good example here. However, its all in C# and when trying to convert it I get a lot of errors that I can not seem to fix.
Imports System.Linq
Imports HelperApp.SPTrackerData
Imports System.Net
Public Class frm_tasks
Private Sub cmdCheck_Click(sender As Object, e As EventArgs) Handles cmdCheckMail.Click
Dim dc As New TeamSiteDataContext(New Uri("http://intranet/_vti_bin/listdata.svc"))
dc.Credentials = CredentialCache.DefaultNetworkCredentials
Dim result = From d In dc.Inventory With { _
Key.Title = d.Title, _
Key.Description = d.Description, _
Key.Cost = d.Cost _
}
For Each d As var In result
Console.WriteLine(d)
Next
End Sub
End Class
I connected my SharePoint to a Service Reference called SPTrackerData as it stated on the website but I can not seem to fix the following:
TeamSiteDataContext: I'm not sure where this is in the original code
so I really have no idea on where or what to replace it with in my code above.
The Linq part: (Dim result =...) I tried my best to form it as i thought it needed to look like but its all wrong.
The one thing that doesn't make since to me is why did I create a service reference and not even use it at all within that code???

TeamSiteDataContext represents the runtime context of the data service.
When you add a reference to an OData-based service (listdata.svc) using Add Service Reference dialog in Visual Studio, a representation of TeamSiteDataContext entity container class that inherits from DataServiceContext is being generated.
Below is provided the converted to VB.Net example:
Sub Main()
Dim dc As New TeamSiteDataContext(New Uri("http://intranet/_vti_bin/listdata.svc"))
dc.Credentials = CredentialCache.DefaultNetworkCredentials
Dim result = From d In dc.Inventory Select New With { _
Key .Title = d.Title, _
Key .Description = d.Description, _
Key .Cost = d.Cost _
}
For Each d In result
Console.WriteLine(d)
Next
End Sub
References
Generating the Data Service Client Library (WCF Data Services)

Related

VB.Net Visual basic Adding a custom event in the Webbrowser control that calls a routine in the main application

I'm trying to create and call a custom event in the webbrowser control and everything that I've tried to do causes one error or another when the webpage executes the code. What I'm doing is adding a button on each row of a table to facilitate removing that row. However, the master list of data is in the application. When the script in the web page executes, I need to update the master list in the application. My thoughts were to call a custom event that will be fired in my application where I can do everything that I need to do. I just can't make this work. here are more details of what I have right now. Here is the html code for a given row:
Dim M As String = "</TD><TD>"
RetStr.Append("<TR ID='" & Me.Manifest & "' name='" & Me.Manifest & "'>")
RetStr.Append("<TD>").Append(CompanyID).Append(M).Append(CompanyName).Append(M)
RetStr.Append(ContactName).Append(M).Append(Address1).Append(M).Append(Address2)
RetStr.Append(M).Append(City).Append(M).Append(State).Append(M)
RetStr.Append(Zip).Append(M).Append(Phone).Append("</TD>")
RetStr.Append("<TD><button onclick='deleteRow(""" & Me.Manifest & """)'>Remove</button></TD>")
Return Replace(RetStr.ToString(), "<TD></TD>", "<TD> </TD>")
Here is the code that is in the function:
Dim HTMLOut As New List(Of String)
HTMLOut.Add("<HEAD>")
HTMLOut.Add(" <SCRIPT language=""VBScript"">")
HTMLOut.Add(" Function deleteRow(rowid)")
HTMLOut.Add(" set row = document.getElementById(rowid)")
HTMLOut.Add(" row.parentNode.removeChild(row)")
HTMLOut.Add(" dispatchEvent(Row)")
HTMLOut.Add(" End Function")
HTMLOut.Add(" </SCRIPT>")
HTMLOut.Add("</HEAD>")
HTMLOut.Add("<BODY>")
HTMLOut.Add(" <TABLE border='1' style='font-size:12;' NAME='Table' ID='TABLE'>")
Here is the code that I have in the application:
Private Sub WB_DocumentCompleted(sender As Object, e As
WebBrowserDocumentCompletedEventArgs) Handles WB.DocumentCompleted
WB.Document.AttachEventHandler("UpdateList", New EventHandler(
Function(ByVal s As Object, ByVal k As EventArgs)
MsgBox("BOO")
Return True
End Function))
End Sub
Any help in any direction, even if it means I need to change how I'm doing all of this, is very welcomed! There is more code then this, it's stripped down to what is needed to convey what I'm doing. I know I'm missing something, I just can't figure out what it is. The end goal is to update the master list in the application hosting the web browser; ideas suggestions and comments are always welcome. As a side note, I'm using the web browser control because the final part of the process is to create a file and sftp it to the vender (the application will do this), and print the report. Thanks!
I figured this out. I needed to create a class object, with the comvisible attribute set and add this to the objectForScripting property of the web browser control.
Imports System.Runtime.InteropServices
<ComVisible(True)> Public Class WBClassCode
Public Sub UpdateStuff(ByVal Data)
'My code goes here... called from the web page.
MsgBox("boo")
End Sub
End Class

Creating a cross domain web service

So, I am very new to creating web services, but have successfully managed to make a simple webservice which returns information as I'd need from a database as List(Of dictionary(of string, string)) object.
For the purpose of testing, I have created this manually, my code looks like this:
Imports System.Web
Imports System.Web.Services
Imports System.Web.Services.Protocols
Imports System.Web.Script.Serialization
<WebService(Namespace:="http://tempuri.org/")> _
<WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)> _
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Public Class test
Inherits System.Web.Services.WebService
<WebMethod()> _
Public Function dic() As String
Dim newDic As New List(Of Dictionary(Of String, String))
Dim one As New Dictionary(Of String, String)
one.Add("id", "1")
one.Add("name", "the name")
one.Add("price", "5.99")
newDic.Add(one)
Dim two As New Dictionary(Of String, String)
two.Add("id", "2")
two.Add("name", "item name two")
two.Add("price", "1299")
newDic.Add(two)
Dim s As New JavaScriptSerializer
Dim str As String = s.Serialize(newDic)
Return str
End Function
End Class
This webservice "dic" gives me serialized string/list looking like this:
[{"id":"1","name":"the name","price":"5.99"},{"id":"2","name":"item name two","price":"1299"}]
I can read this in VB code like this:
Sub loadMe() Handles Me.Load
Dim t As New websvce.testSoapClient
Dim d As String = t.dic
Dim s As New JavaScriptSerializer
Dim d2 = s.DeserializeObject(d)
Response.Write(d2(1)("name") & "<hr>")
End Sub
which gives me the output of the "name" element with index "1". It works fine.
However, unsurprisingly, it does not work when trying to grab this info with jQuery using code as follows:
$(document).ready(function () {
$.getJSON('URL/test.asmx/dic', function (data) {
alert(data);
});
});
So I have spent a good part of the day Googling this, and found all kinds of comments and conversations telling me about why cross domain scripting is not allowed and that there are ways round it using Proxies, adding headers to pages and so on... but... no conclusive solution to the problem.
Here's some of the SO questions I have found:
Origin http://localhost is not allowed by Access-Control-Allow-Origin
How to implement "Access-Control-Allow-Origin" header in asp.net
There's many more, but I cannot find an absolute solution, which fits my criteria. I want to output data in a format similar to that above, and access it from another domain with jQuery.
The easiest work around I have found is to write a handling page which runs on the receiving server, simply loading the data as per my VB code example above and operating as a webMethod on that server to spit out JSON, but I'd rather the whole thing could be handling by the web service, thus no need to run extra files on the consuming server.
EDIT; actually, I do also need to be able to perform POST operations.

How to send a class through named pipe in VB.net

Using VB2008, I have 2 applications on 2 computers that needs to communicate. I setup a named pipe and so far, it's working. I can send strings, back and forth between those 2 programs.
Now, I need to be able to send a class, or an object. I have read somewhere that Serialization is the way to go. So, on the client, I have:
Public Class cTest
Dim Var1 As Boolean
Dim Var2 As String = "a test"
Dim Var3 As New Collections.ArrayList
Public Sub AddItem(ByVal Item As String)
Var3.Add(Item)
End Sub
End Class
Private Sub Button8_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button8.Click
Dim oClasse As New cTest
oClasse.AddItem("StarWars")
oClasse.AddItem("StarTrek")
oPipe.SendToPipe(oClasse)
End Sub
End Class
Public Sub SendToPipe(ByVal test As cTest)
Dim xmlTest As New Xml.Serialization.XmlSerializer(GetType(cTest))
xmlTest.Serialize(pipeClient, test)
End Sub
On the server side (on the remote computer):
Public Function ReadString() As String
Dim len As Integer = 0
len = CType(ioStream.ReadByte(), Integer) * 256
len += CType(ioStream.ReadByte(), Integer)
Try
Dim serializer As New Xml.Serialization.XmlSerializer(GetType(cTest))
Dim Test As cTest
Test = CType(serializer.Deserialize(ioStream), cTest)
Catch ex As Exception
End Try
End Function
The serializer.Deserialize throw an exception saying the XML format is not correct.
what I'm doing wrong?
thanks for your time and help
finally, after a lot of testing and googling, I figured it out:
when using the following code on the client side it works:
Dim oClasse As New cTest
oClasse.AddItem("StarWars")
oClasse.AddItem("StarTrek")
Using PStream As IO.Pipes.NamedPipeClientStream = New IO.Pipes.NamedPipeClientStream(".", "VisionEnginePipeRead1", PipeDirection.Out, PipeOptions.None, TokenImpersonationLevel.None)
PStream.Connect()
Dim xmlTest As New Xml.Serialization.XmlSerializer(GetType(cTest))
xmlTest.Serialize(PStream, oClasse)
End Using
and this, on the server side:
Dim Test As cTest
Using PStream As NamedPipeServerStream = New NamedPipeServerStream(pipeName, PipeDirection.In, 1, PipeTransmissionMode.Byte, PipeOptions.None)
PStream.WaitForConnection()
Dim serializer As New Xml.Serialization.XmlSerializer(GetType(cTest))
Test = CType(serializer.Deserialize(PStream), cTest)
End Using
If I were you I would use WCF Self Hosted Services and let the two communicate using callbacks
This started as a comment but I was running out of room. I am no expert on named pipe communications but, it has been a couple hours, and it may be that that is not really the problem.
You need to first test the serialization/deserialization in the same application. In other words start by taking the pipes out of the picture. This will isolate whether this is a serialization issue or a named pipe issue. Assuming that you code will work when done in the same application, then you need to compare the xml generated by the two applications - have them both do a Serialize. If the xml is identical (which I doubt) then pass it through the pipe and compare it again.
Going further out on a limb here but you may see that the namespace is different for the ctest object. If this is the case it may help to define your shared classes in a library which is shared between the two applications.

SharePoint: GetListItems soapserverException being thrown because of Query

I am using designing a Windows Form application using VB.net. I trying to have the application return the number of rows in a specific SharePoint List. Everything works perfectly when I I remove the ndQuery.InnerXml code; however, I want to filter the list before I get the count. The two columns I want to filter are "Assigned Employee" and "status." I looked at many different posts here on Stack(SharePoint SoapServerException calling GetListItems web service), but my Exception is relating to the Query. The detail of the soapserverException is: "One or more field types are not installed properly. Go to the list settings page to delete these fields: 0x81020014."
I tried going to the relationship page, but I could not browse to it:
(url)/Relationships%20List/allitems.aspx
Can any one see a problem with the Query code?
Imports System
Imports System.IO
Imports System.Net
Imports System.Xml
Imports <xmlns="rs">
Public Class Form1
Dim i As Integer
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim listService As New getListItems.Lists
listService.Credentials = CredentialCache.DefaultCredentials
listService.Url = "http://(servername)/_vti_bin/Lists.asmx"
Dim xmlDoc = New System.Xml.XmlDocument()
Dim ndQuery As XmlNode =
xmlDoc.CreateNode(XmlNodeType.Element, "Query", "")
Dim ndViewFields As XmlNode =
xmlDoc.CreateNode(XmlNodeType.Element, "ViewFields", "")
Dim ndQueryOptions As XmlNode =
xmlDoc.CreateNode(XmlNodeType.Element, "QueryOptions", "")
ndQueryOptions.InnerXml =
"<IncludeMandatoryColumns>FALSE</IncludeMandatoryColumns>"
ndViewFields.InnerXml = "<FieldRef Name='Assigned Employee'/><FieldRef Name='Status'/>"
ndQuery.InnerXml = "<Where><And><Contains><FieldRef Name ='Assigned Employee'/><Value Type='Text'>Engineer</Value></Contains><Contains><FieldRef Name='Status'/><Value Type='Text'>New</Value></Contains></And></Where>"
Try
Dim ndListItems As XmlNode =
listService.GetListItems("Requests", Nothing, ndQuery, _
ndViewFields, Nothing, ndQueryOptions, Nothing)
Dim n1 As XmlNode = ndListItems.Item("rs:data")
Dim a As String = n1.Attributes("ItemCount").InnerText
'Attempted For each loop, but not needed:
'Dim listItemCount As String
'Dim innerXML = New System.Xml.XmlDocument
'innerXML.LoadXml(ndListItems.InnerXml)
'Dim rows As XmlNodeList = innerXML.GetElementsByTagName("rs:data")
'For Each (XmlNode Attribute In rows)
'Next
Label1.Text = a
Catch ex As System.Web.Services.Protocols.SoapException
Label1.Text = ("Message:" + ControlChars.Lf + ex.Message +
ControlChars.Lf +
"Detail:" + ControlChars.Lf + ex.Detail.InnerText +
ControlChars.Lf +
"StackTrace:" + ControlChars.Lf + ex.StackTrace)
End Try
End Sub
End Class
You may need to replace the spaces in the field names with _x0020_ e.g.
<FieldRef Name='Assigned_x0020_Employee'/>
The Name attribute takes the field's internal name so double check that's what you're using.
When I have encountered the fun "one or more field types are not installed properly" error in the past it has usually been due to my CAML WHERE criteria indicating a field is of a certain type when it is not (e.g. I indicate Value type="Text" when it is actually a lookup).
If you go and get CAML Query Builder (free) from U2U, you can point it at your site (using the built in web services of SharePoint) and build your CAML query using their drag and drop designer. Once you have the query working there just click on the Edit tab and it will show you the exact CAML that SharePoint expects. My guess is you will find a field type incorrectly set. Whole process should take about 10 minutes after you install it.
I discovered the problem when breaking apart the query statement into two parts:
'ndQuery.InnerXml = "<Where><Eq><FieldRef Name ='Assigned_x0020_Employee'/><Value Type='Text'>Engineer</Value></Eq></Where>"
'ndQuery.InnerXml = "<Where><Eq><FieldRef Name ='Status'/><Value Type='Text'>New</Value></Eq></Where>"
I figured out that although one of the Columns in the SP list was named "Assigned Employee," the actual FieldRef Name was just employee. When I modified the code to include that, the error went away. I was spending all my time changing the Value Type, instead of looking at the FieldRef Name
Final Conclusion:
The "one or more field types are not installed properly" error not only gets returned if the "Value Type" is incorrect, but also when the "FieldRef Name" contains the wrong label.
Final working code line:
ndQuery.InnerXml = "<Where><And><Eq><FieldRef Name ='Employee'/><Value Type='Text'>Engineer</Value></Eq><Eq><FieldRef Name='Request_x0020_Status'/><Value Type ='Text'>New</Value></Eq></And></Where>"

Visual Basic: dynamically create objects using a string as the name

Is there a way to dynamically create an object using a string as the class name?
I've been off VB for several years now, but to solve a problem in another language, I'm forced to develop a wrapper in this one. I have a factory method to dynamically create and return an object of a type based on input from elsewhere. The provided input is meant to be the class name from which to create an object from. Normal syntax means that the entire class has to be explicitly spelled out. To do it this way, there could literally be hundreds of if/then's or cases to handle all the available class/object choices within the referenced libs:
If c_name = "Button" then obj = new System.Windows.Forms.Button
If c_name = "Form" then obj = new System.Windows.Forms.Form
....
I'm hoping instead to reduce all this case handling to a single line: IE...
my_class_name = "whateverclass"
obj = new System.Windows.Forms.my_class_name()
In PHP, this is handled like so...
$my_class_name = "whateverclass";
$obj = new $my_class_name();
Edit: Looking at some of the answers, I think I'm in way over my head here. I did manage to get it working using this CreateInstance method variation of the Assembly class, even though I'm more interested in this variation giving more options, including supplying construct parameters...
my_type_name = "System.Windows.Forms.Button"
asmb_name = "System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
button1 = Reflection.Assembly.Load(asmb_name).CreateInstance(my_type_name)
In other words, it takes a method to do this, and not any inherent language syntax? This Activator variation also worked when the full assembly string and class path is used. I'm suspicious CreateInstance may not have the full ability to let me treat objects as if they were called normally, ie obj = new System.Windows.Forms.Button. This is why I can't use simply CreateObject. If there is no natural language feature allowing you to substitute a class name for a string, does anyone have any insight into what sort of limitations I can expect from using CreateInstance?
Also, is there even a difference between basic Activator.CreateInstance (after Unwrap) and Assembly.CreateInstance methods?
This will likely do what you want / tested working; switch the type comment at the top to see.
Imports System.Reflection
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' Dim fullyQualifiedClassName as String = "System.Windows.Forms.TextBox"
Dim fullyQualifiedClassName As String = "System.Windows.Forms.Button"
Dim o = fetchInstance(fullyQualifiedClassName)
' sometime later where you can narrow down the type or interface...
Dim b = CType(o, Control)
b.Text = "test"
b.Top = 10
b.Left = 10
Controls.Add(b)
End Sub
Private Function fetchInstance(ByVal fullyQualifiedClassName As String) As Object
Dim nspc As String = fullyQualifiedClassName.Substring(0, fullyQualifiedClassName.LastIndexOf("."c))
Dim o As Object = Nothing
Try
For Each ay In Assembly.GetExecutingAssembly().GetReferencedAssemblies()
If (ay.Name = nspc) Then
o = Assembly.Load(ay).CreateInstance(fullyQualifiedClassName)
Exit For
End If
Next
Catch
End Try
Return o
End Function
I'm pretty sure Activator is used for remoting. What you want to do is use reflection to get the constor and invoke it here's an example http://www.eggheadcafe.com/articles/20050717.asp
EDIT: I was misguided about Activator until jwsample corrected me.
I think the problem your having is that your assembly is the one that GetType is using to try and find Button. You need to call it from the right assembly.
This should do it
Dim asm As System.Reflection.Assembly = System.Reflection.Assembly.LoadWithPartialName("System.Windows.Forms")
Dim obj As Object = Activator.CreateInstance(asm.GetType("System.Windows.Forms.Button"))
Take a look at the Activator.CreateInstance(Type) method.
If your input is the name of a class you should be able do this:
Dim obj As Object = Activator.CreateInstance(GetType("Name_Of_Your_Class"))
You'll have to fiddle with the GetType call to make sure you give it enough information but for most cases just the name of the class should work.
Here is a really easy way I have found while rummaging through the internet:
dynamicControl = Activator.CreateInstance(Type.GetType("MYASSEMBLYNAME." + controlNameString))