Get data from WCF - c#

I'm so confused. Although I have a fair background in C#, this is my first exposure to WCF.
I have a C# desktop application that does a few functions such as getting data from a local xml file, and other various functions, which I don't need to explain here because they don't relate to this question. Now I need to use a URL for a WCF Service to get some other data to use in my application.
The more I read about WCF online and go through the tutorials the more confused I get. That's why I'm requesting a really simple, clear, straight-forward answer to my questions here. I'm not looking for anything fancy or advanced like setting up a WCF Service Library or WCF Service Application. I'm simply a beginner to WCF who wants to use a WCF service URL in my existing C# desktop application to get some data. The WCF service was provided to me by someone else, and is properly working. Please keep in mind when answering this question that I am new to WCF, so a beginner level answer to this topic is best.
This is what I've don so far:
Created a C# Windows Forms Application that properly builds and runs. The application has a few custom classes, a local xml file for data retrieval, and some event handlers for button clicks and such in the Form1 class.
I added the WCF service reference to my project (i.e., right-click project > Add Service Reference > paste in url > Go > Ok.
Added the System.Data.Services.Client reference to my project. Although I don't know if this is even needed.
In my Form1 class where the event handlers are, I added the following using directives: using MyProject.theService and using System.Data.Services.Client.
Added these global variables at the beginning of the Form1 class:
private Uri svcUri = new Uri("http://www ... service.svc");
private ServiceClient context;
In the Form1 class, in a button event, I have the following code:
-
private void btnWebService_Click(object sender, EventArgs e)
{
ServiceClient client = new ServiceClient();
Student s = new Student();
// this is implemented as follows in the student class: public Fee[] Fees { get; set; }
Fee f = new Fee();
// need some logic here to get the data using the client object
client.Close();
}
There is a method of the client object called GetFees (client.GetFees()) and I'm assuming it is the most logical choice to use this method to get the data I need (which is the fees associated with the students). Visual Studio gives this description of the method:
theService.Student[] ServiceClient.GetFees(theService.Student[] students)
What I'd like is when I click the button and fire the btnWebService_Click event, I call the service, retrieve the needed data, store it in the appropriate object, and have the data to use however I need.
My question are:
On step 6, am I moving the right direction?
Have I missed any steps in order to made the WCF call work?
The GetFees() method is confusing me. How do I write the correct C# code to use it without errors?
I've tried writing this line of code in the event handler:
f = client.GetFees(s.Fees[0]);
But I get the following errors in Visual Studio:
The best overloaded method match for 'MyProject.theService.ServiceClient.GetFees(MyProject.theService.Student[])' has some invalid arguments
Argument 1: cannot convert from 'MyProject.Fee' to 'MyProject.theService.Student[]'
What is am I doing wrong here? Or is this line even close to anything I need?
I've purposefully excluded the full url of the WCF service from this question. If it helps to have it to properly answer this question please let me know and I will give it to you. Also, there is a wsdl url. Let me know if having it will help you answer my questions.
Thank you in advance for reading all this. I welcome and appreciate any kind of help you can provide.
------------------------- EDIT -------------------------
Based on some of the help I've received I'm getting very close to a solution. But I still have one issue.
This code compiles and runs:
private void btnWebService_Click(object sender, EventArgs e)
{
ServiceClient client = new ServiceClient();
theService.Student s = new theService.Student();
theService.Student[] stds = new theService.Student[30];
stds[0] = s;
var ret = client.GetFees(stds);
client.Close();
}
However, I get the following error from Visual Studio:
Invalid StudentID(=0). StudentID must be greater than 0.
This error occurs because the values in stds[0] are null.
In a different part of my program, I have a LINQ query that grabs the student data from an xml file and stores it in a List<Student> students object.
So looking at the code above, my next step would be to assign the values from students to stds[0]. The problem I cannot figure out is some issue with casting or conversion. How do I assign student objects from List to a theService.Student[] object so that I can provide the service some data to look up?
I've tried doing this:
stds[0] = (theService.Student)students[0];
But of course I get this error:
Cannot implicitly convert type 'MyProject.Student' to 'MyProject.theService.Student'
I know this might seem really simple and obvious to some, but I cannot figure it out. I can't find the answer on Google. Someone please help.

You have your local information stored in an object called Student, and the service expects an object called Student but they are not the same thing.
I recommend creating either:
a) creating an extension method on YOUR student object to convert it to a service student object
b) creating an explicit conversion for your student object into a the service student object
but, the long way will be to do something like:
theService.Student s = new theService.Student();
s.Name = students[0].Name; //these are example fields
s.Id = students[0].Id; //these are example fields
var ret = client.GetFees(new theService.Student[] { s });

You're on the right track, you're just not calling the service as expected. The service expects you to pass in an array of Student objects, and it will return an array of Student objects.
theService.Student[] ServiceClient.GetFees(theService.Student[] students)
Try something like
var stds = new Student[];
stds[0] = s; // the Student you set up
var ret = client.GetFees( stds ); // ret is an array of Student
f = ret[0]; since you only passed a single student in, the 1st item in the return array should be your student with fees
Now, look at f.Fees for your data.
You can shorten this code quite a bit; I wanted to show discrete steps.

Related

How to load an Entity Framework data object without explicitly setting each property

I want to be able to do something like the following:
var book = new Book();
book.LoadByPrimaryKey(id); //returns bool
The issue I am coming across is I can't figure out if there is a simple way to load data into an object generated using Entity Framework. I understand how to grab the information needed to fill the object, but is there a simple way to fill out all the properties of an object without explicitly going through each property and setting it to the desired value? In C# I cannot simply type:
this = db.Books.Single(d => d.BookId == id);
I instead have to explicitly set each property:
var book = db.Books.Single(d => d.BookId == id);
this.Title = book.Title;
this.PageCount = book.PageCount;
...
Is there a way around doing this when wanting to load up an object? Maybe something with a DbDataReader? I have used the data reader to load DataTables, but can't figure out how to use them to populate an object. Maybe I'm over thinking it.
When you need to copy all of the properties from one object to another you can
Just write the code (typing practice)
Generate the code using a T4 Template
Use Reflection
Use Automapper
As David Browne previously answered:
Just write the code (typing practice)
Generate the code using a T4 Template
Use Reflection
Use Automapper
The answer he gave you is correct. But I'm want to extend it and explain why.
First, let put some concept here. When we go further in programming techniques, sometimes, the working answer, it not enough. Although what you trying to do is a valid solution for the problem, there is some issue with it.
The is a concept that is called S.O.L.I.D. The first letter (S) stands for Single Responsibility Principle. This means that one object should have only one responsibility.
The problem in your approach is you are putting multiple responsibilities in a single object:
Hold/Transport information about a book.
Load from a remote server (in this case a DataBase) information about a book.
You probably googled this issue before post here, and I suspect you found nothing useful. Now the reason you found nothing is because this is a bad approach, it goes against the SOLID concepts, and it breaks several interation with possible Design Patterns. So this is why you probably found nothing, there is no previous conceived tool of workaround to this problem, because this is a discouraged approach, so no one, with a little understand of program techniques, will help you.
Therefore, we go back to the answer that David Browne gave you. To use Automapper (the simplest of the suggestions). You need to change your approach. Consider to separate each responsibility in a different class:
class BookDA // DAO = data access
{
private MyDbConnection db;
public BookTO Get()
{
var book = db.Books.Single(d => d.BookId == id);
return book;
}
}
class BookTO // TO = transport object
{
public string Name { get; set; }
}
In the code above each responsibility is associated with a different class. This answer became too long but I hope it helps.

C# Dynamic List Class

I have a bit of a weird issue. Working in C# script with SSIS I have developed a need to build a List based off Dynamic Data.
Background
To explain it, a script task is fired that has a variable API URL, this goes off and pulls a JSON string back and then throws it into a strongly typed list using the following code.
var listobject = get_APIData<ApplicationOneDataSet>(url)
The class that does this is long winded and not really needed in the context of this issue.
ApplicationOneDataSet is a strongly typed match to one of the possible JSON results returned by get_APIData.
Now I have a need to change ApplicationOneDataSet to ApplicationTwoDataSet dynamically based on which API URL I pass to the script.
So what I have done is send through a second variable to the script called class name which contains the string "ApplicationDataSetOne" or "ApplicationDataSetTwo" based on which context I call it under.
The Question
My question is how can I dynamically vary this line:
var listobject = get_APIData<ApplicationOneDataSet>(url)
With the string variable passed into the script.
My original thinking was something along the lines of this:
var ClassType = (string) Dts.Variables["AppClassName"].Value;
Type type = Type.GetType(ClassType);
var listobject = get_APIData<type>(url)
Though it doesn't seem to like that. Any tips would be great!
As long as there is exactly two types you can use and you know them at compile time, I would not look further than a simple if. It works, it's easy, everyone understands it.
You can do it totally dynamic at runtime, but that's a huge pain in the... where you don't want it to be. If you really want to go down that rabbit hole, you can find more information here.
I'm not sure I fully understood what you are trying to do, but how about writing an interface ApplicationDataSet and then making a list of it? This way your list is going to be able to contain both types of data.

twilio twimlresult post to sql server

So, adapting some of the code from the tutorial here:
I have got a twilio app up and running and it correctly posts and inserts calls into my sql server, although I am trying to add additional fields to be inserted and I ran into some issues. In my controller, this is the method i am using:
[HttpPost]
public TwiMLResult Create(
[Bind(Include = "QuestionId,RecordingUrl,Digits,CallSid,From")]
Answer answer)
{
_answersRepository.Create(answer);
var nextQuestion = new
QuestionFinder(_questionsRepository).FindNext(answer.QuestionId);
return TwiML(nextQuestion != null ? new Response(nextQuestion).Build() :
ExitResponse);
}
My question is two parts. First, how can I add more fields to be added to my sql table? I tried adding StartTime, EndTime, Duration after ,From and adding it to the Model, synced my database so I can see the columns on the table but nothing actually get's inserted. I put the data types as string so maybe that was the issue? I could not tell from the twilio documentation what datatype those fields wer.
The second part of the question is can I put custom fields into that Bind(Include) statement? For instance, can I create a variable called Name and then have the TwiMLResult Create send a string Name along with the twilio data with it as well? Of course, I would add it to the model class and thus to the table.
I guess my problem is is that I don't understand what is happening with the TwiMLResult Create method very well. What is happening exactly? This method here is what is actually RECEIVING the data coming from twilio, correct? and the _answersRepository.Create is what writes it to the database? So I should be able to add more fields and have them written to the db just fine I would think. I just am not sure why the StartTime, EndTime, Duration information isn't coming through to this point. Similarly, I am not sure how to add a custom variable, for instance, to pass the person's name to this point and have it written to the db.
I hope this all makes sense and isn't too convoluted to understand. Thank you in advance everyone! I really appreciate the help!
Syd
EDIT: Basically, I determined that those fields do not come through and thus were passing null values. To answer the second part of my question, you can definitely pass any query values and record them (which is what I ended up doing).

Coding to make a SQL table from an InfoPath 2003 form without knowing the fields in advance

Using: InfoPath 2003 (and its XML), Microsoft SQL Server 2005, Visual Studio 2005, C# (to make a web service)
I've been trying to find something that does this already, and either my Google skills are failing or it's not actually possible, because I can't believe this hasn't already been needed by someone.
I am attempting to make a web service that takes an InfoPath form, gets the list of all the fields from the form (and their associated expected data types if the user bothered with validation), and creates a table in a SQL database with the same fields and expected types (probably using varchar as a default type where validation wasn't used). I can't just list the fields ahead of time, because in theory, managers and engineers will be making new forms for all sorts of purposes and I need to avoid confusing them or giving them direct access to the server.
I've never done anything of this sort before, nor have I used XML (or C#, for that matter). Before I drive myself crazy trying to make everything work, I need to know: is this possible? I know XML documents are basically made of user-defined tags, and I don't know if there's any way to distinguish form fields from any other tags associated with rendering the document properly. I also don't know if there are methods available for getting the expected data types. If this stuff is possible, any guidance in how would be appreciated.
Update
Judging from an InfoPath form at the XML level, it seems that all of the fields are contained in the <my:myFields> tag. It also contains the <xd:SchemaInfo> tag, so now I've got to figure out how to access all of the fields while ignoring that one.
I still don't know if I'm trying to do something that's weird, impossible for another reason, or bad practice, so advice from people who know things is always welcome.
Yes, this is totally possible. The only thing you need to make sure is, that the managers/engineers submit their form against your web service as string like shown in this screenshot.
The Reason why you need to submit the form as string is simple - you cannot configure IP to send XmlDocument object's directly. It is possible, however you need custom code in each form you/your cowokers create, so i'd suggest using the no-code solution.
Heres how you could implement the web service method.
[WebMethod]
public void CreateTable(string infoPathData)
{
var doc = new XmlDocument();
doc.LoadXml(infoPathData);
//gets the namespace uri - it is unique for each form
string nsUri = doc.ChildNodes[3].Attributes["xmlns:my"].Value;
var nsManager = new XmlNamespaceManager(doc.NameTable);
nsManager.AddNamespace("my", nsUri);
//select the myField node
var root = doc.SelectSingleNode("my:myFields", nsManager);
var sqlStatement = new StringBuilder();
sqlStatement.Append("CREATE TABLE ....");
foreach (XmlNode n in root.ChildNodes)
{
//n.Name - gets the name of the node (incl. NS)
//n.InnerText - gets the field value
//append to sqlStatement
}
//execute sql statement ...
}
You build an XmlDocument from the submitted IP data and then iterate it's fields. Depending on your requirements, you might also need to iterate child-nodes (i.e. if the form includes folders/repeating tables etc.) but thats really up to you ;-)
If you never worked with XmlDocument's before, be sure to check out this link http://msdn.microsoft.com/en-us/library/system.xml.xmldocument.aspx
You will need to enforce some specific rules to people who use your web service like what happens when someone renames "my:myFields" to "my:myBlaBla" (which is possible) and submits his/her form to your web service. Also i suggest very heavy error-logging, because things can (and will!) go wrong with such a generic approach.
The only problem which i can think of is how to determine the data-type of each field because it is not included in the InfoPath form data. You could try the usual C# Conversion methods (like Int32.TryParse etc).
Hope this helps :-)

Global variable lost which results on failure during function assigning

Currently I'm developing a dashboard for the company that I'm working for. The functionality of this dashboard is not interesting for this problem. This dashboard is build up like:
Asp.net page (with a codebehind ofcourse)
Class where webmethods are defined
Javascript external file (with all the funcitonality of the dashboard, this dashboard works fully clientside)
For the rest I'm working with Visual Studio 2010 Ultimate with a TFS (team foundation server) environment and we make use of the jQuery library and .NET framework 4.0 (C#).
Alright, with that information i hope i can explain my problem. The external javascript file contains three classes. I will name them now ClassMain, ClassSub1, ClassSub2. The classes ClassSub1 and ClassSub2 are derived from ClassMain by doing the following javascript command:
ClassSub1 = new ClassMain();
After this instantiation of the ClassMain other properties and methods of ClassSub1 are loaded. The ClassMain can communicate with the properties and methods of ClassSub1 and ClassSub1 can communicate with ClassMain. So this means that they act like one big class with all kinds of functionality.
I explain this because i think my problem lays here but I'm not sure about it. The classes ClassSub1 and ClassSub2 are getting instantiated in the codebehind of the asp.net page. The following snippet explains it:
StringBuilder javascriptBlockBuilder = new StringBuilder();
javascriptBlockBuilder.AppendFormat("var {0};", this.Id);
javascriptBlockBuilder.AppendFormat("Sys.Application.add_load({0}LoadHandler);", this.Id);
javascriptBlockBuilder.AppendFormat("function {0}LoadHandler() {1}", this.Id, "{");
javascriptBlockBuilder.AppendFormat("{0} = new ClassSub1('{0}');{1}", this.Id, "}");
javascriptBlockBuilder.AppendFormat("var {0};", this.OtherId);
javascriptBlockBuilder.AppendFormat("Sys.Application.add_load({0}LoadHandler);", this.OtherId);
javascriptBlockBuilder.AppendFormat("function {0}LoadHandler() {1}", this.OtherId, "{");
javascriptBlockBuilder.AppendFormat("{0} = new SubClass2('{0}');{1}", this.OtherId, "}");
Page.ClientScript.RegisterStartupScript(this.GetType(), "ClassInitialization", javascriptBlockBuilder.ToString(), true);
In this snippet I create a global variable on the page and assign that class to it. The ClassMain gets the same id as ClassSub1 and ClassSub2 so that they make use of the same variable because like i said a few lines up these classes must act as one class (ClassMain and the ClassSub).
This works also but here comes also the problem. Before executing the above snippet (or after) i have some statements like this:
this.myButton.Attributes.Add("onclick", string.Format("{0}.myJavascriptFunctionality();", this.id));
The functionality gets attached to divisions, buttons, etc.
Ok, now I'm going to render my page and the page loads perfectly, but when I click one of the buttons, divisions, etc. Is it telling me that it requires an object. Somehow my global variables with the ClassSub1 and ClassSub2 are lost and now it can't execute my JavaScript commands.
So my question is, how is it happened that my variables are lost? I hope that my explanation is enough to understand.
It looks like you are calling ClassSub1.myJavascriptFunctionality() in the onclick event of myButton.
ClassSub1 is the function definition / prototype - whatever OOP mechanism you are using. You would have to specify the variable name, not the classname.
like so
this.myButton.Attributes.Add("onclick", String.Format("{0}.myJavascriptFunctionality();", this.Id));
I have found an solution for my problem. The problem occured that my references between the two classes (ClassMain and ClassSub) are referencing to the same variable which results in an error that javascript cannot handle. What did I do to fix this problem?
I have found the answer on this page:
http://www.cristiandarie.ro/asp-ajax/JavaScriptPrototypeInheritance.html
ClassSub1.prototype = ClassMain;
ClassSub1.prototype.constructor = ClassSub1;
And during my construction of the object I did the following call:
ClassMain.call(this, id);
Where 'this' is my current class and I pass an 'id' so that i can reference then to my mainobject.

Categories