wcf web service only generates async methods when consuming it in xamarin.forms app - wcf

i am trying to connect my xamarin.forms app to sql server. i know that i have to use a webservice to do that. i am using wcf web service. the problem is that i only got async methods after adding it as a connected service to my app. like the problem in this question: Xamarin.Forms Add Connected Service on WCF only generated async method the thing is i can't use its answer because i don't have the generate synchronous operations option, i found another answer in this: WCFclient operation only Async .Net core 2.0 but i really still don't know how to use the async methods. like how do i get the result of the operation to perform my login when clicking a button. this is my code for the wcf webservice:
Iuserlogin.cs:
[ServiceContract]
public interface Iuserlogin
{
[OperationContract]
[WebInvoke(BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json, Method = "POST")]
DataTable login(string username, string pass);
}
userlogin.svc.cs:
public class userlogin : Iuserlogin
{
public DataTable login(string username, string pass)
{
DataTable dt = new DataTable();
dt.TableName = "summary_req";
SqlConnection con = new SqlConnection("server=DESKTOP-CPOJ94O\\MSSQLSERVER1;database=users;integrated security=true");
con.Open();
SqlCommand cmd = new SqlCommand("SELECT username, password FROM hjk where CONVERT(VARCHAR, username)=#username and CONVERT(VARCHAR, password)=#password", con);
cmd.Parameters.AddWithValue("#username", username);
cmd.Parameters.AddWithValue("#password", pass);
SqlDataAdapter da = new SqlDataAdapter(cmd);
da.Fill(dt);
return dt;
}
}
}
this is my trial to use the async functions in my app:
MainPage.xaml.cs:
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
private void SignIn_Clicked(object sender, EventArgs e)
{
ServiceReference1.IuserloginClient cs = new ServiceReference1.IuserloginClient();
string user_name = username.Text;
string pass = password.Text;
ServiceReference1.loginRequest loginreq= new ServiceReference1.loginRequest(user_name, pass);
ServiceReference1.loginResponse response = cs.loginAsync(user_name, pass).Result;
}
}
}
i don't know what to do next. how do i continue to know if the user can login or not. how do i get a datatable result from the wcf functions.
thanks in advance.

Related

How to create single instance for multiple endpopints in wcf

Scenario:
I have single instance type of wcf service. which keep data in memory.
Clients call the service and get data without hitting the db.
Wcf Service is host in windows service.
In windows service i have used timer, on the bases of which wcf service hit the database and refresh the data.
Now problem is that when call of refresh take place, request of data client impacted and got time out.
Now i have tried two endpoints. One for consumer and second for refresh.
Both working well, but even refresh endpoint refresh the data. consumer endpoint gives old data whether refresh endpoint showing correct data.
Code Example
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class Service1 : IService1
{
List<string> Name;
public Service1()
{
Name = new List<string>();
CollectData1();
}
public List<string> CollectData()
{
CollectData1();
return Name;
}
public List<string> CollectData1()
{
List<string> _name = new List<string>();
string connectionString = ConfigurationManager.ConnectionStrings["DBConnectionString"].ConnectionString;
using (SqlConnection sqlConnection1 = new SqlConnection(connectionString))
{
using (SqlCommand cmd = new SqlCommand())
{
cmd.CommandText = "select name from test";
cmd.Connection = sqlConnection1;
sqlConnection1.Open();
using (SqlDataReader reader = cmd.ExecuteReader())
{
if (reader.HasRows)
{
while (reader.Read())
{
string a = Convert.ToString(reader[0]);
_name.Add(a);
}
}
}
}
}
Name = _name;
return Name;
}
public List<string> GetData()
{
return Name;
}
}

List<class> Method exposing WCF service in MVC 4

I am working on MVC 4 and WCF Class Library I had added method that is return List and I have added reference of WCF services.
now I am creating proxy of ServiceReference1 then I am not able to get this ServiceReference1 object.
if I changed return type to string then it working..
I had tried changing all collection type but I dint get ServiceReference1 object.!
where I am wrong or what is the solution.?
My WCF code is here
public class BuildTrackerService : IBuildTrackerService
{
public List<Property> DoWork()
{
DataTable dt = new DataTable();
List<Property> objProperty = new List<Property>();
SqlConnection conn = DbConnection.GetConnection();
SqlDataAdapter adpt = new SqlDataAdapter("[GetPropertyDetail]", conn);
adpt.SelectCommand.CommandType = CommandType.StoredProcedure;
try
{
conn.Open();
adpt.Fill(dt);
}
catch (Exception) { throw; }
finally
{
conn.Close();
adpt.Dispose();
}
objProperty = DataTableHelper.ConvertTo<Property>(dt);
return objProperty;
}
}
MY MVC 4 ActionResult is like
public ActionResult Index()
{
ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application.";
/*
==> this ServiceReference1 is not accessible here....!
var obj = new ServiceReference1.BuildTrackerServiceClient();
*/
var objct = obj.DoWork();
return View();
}
I had tried with !
With a WCF web service you can transport only primitive types. Changes your list to an array and try it again.

Can you configure default settings for the XmlWriter used by WCF?

Is there any way to configure the default XmlWriter used by WCF service with DataContractSerializer when serializing data?
Out of the box WCF service using DataContractSerializer is losing the new lines (\r\n).
[Edit: I apologize for the confusion. Out of the box WCF DOES NOT lose the new lines.]
I am able to make XmlWriter encode the new lines to 
 by using XmlWriterSettings (NewLineHandling.Entitize), but I want to make WCF behave the same way when serialize my object.
public string Serialize<T>(T object)
{
var serializer = new DataContractSerializer(typeof(T));
using (var stringWriter = new StringWriter())
{
var settings = new XmlWriterSettings { NewLineHandling = NewLineHandling.Entitize };
using (var xmlWriter = XmlWriter.Create(stringWriter, settings))
{
serializer.WriteObject(xmlWriter, object);
string xml = stringWriter.ToString();
return xml;
}
}
}
If you want to use a different XmlWriter, you'll need to use a custom message encoder. The sample at http://msdn.microsoft.com/en-us/library/ms751486.aspx shows how you could write one.
But I've never seen WCF losing the \r\n characters - it properly entitizes the \r into 
, at least all the times I checked. When I run the code below it shows the characters properly returned:
public class StackOverflow_12205872
{
[ServiceContract]
public interface ITest
{
[OperationContract]
string Echo(string text);
}
public class Service : ITest
{
public string Echo(string text)
{
return text;
}
}
public static void Test()
{
string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
host.AddServiceEndpoint(typeof(ITest), new BasicHttpBinding(), "");
host.Open();
Console.WriteLine("Host opened");
ChannelFactory<ITest> factory = new ChannelFactory<ITest>(new BasicHttpBinding(), new EndpointAddress(baseAddress));
ITest proxy = factory.CreateChannel();
string str = proxy.Echo("Hello\r\nworld");
Console.WriteLine(str);
Console.WriteLine(str[5] == '\r' && str[6] == '\n');
((IClientChannel)proxy).Close();
factory.Close();
Console.Write("Press ENTER to close the host");
Console.ReadLine();
host.Close();
}
}
And Fiddler shows this request being sent:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Header></s:Header><s:Body><Echo xmlns="http://tempuri.org/"><text>Hello
world</text></Echo></s:Body></s:Envelope>
The response also contains the entitized CR character. Can you share more details about your configuration (including binding)?

Exposing a WCF Service REST-fully

I have created a brand new WCF Service. I created this service by just saying Add New Item... -> WCF Service in Visual Studio. I then edited the contract slightly to look like the following:
[ServiceContract]
public interface IMyService
{
[OperationContract]
[WebGet(UriTemplate = "/Authenticate/{username}/{password}", ResponseFormat = WebMessageFormat.Json)]
bool Authenticate(string username, string password);
}
My operations looks like the following:
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
[ServiceBehavior(IncludeExceptionDetailInFaults = false)]
public class MyService : IMyService
{
public bool Authenticate(string username, string password)
{
try
{
return false;
}
catch (Exception ex)
{
throw new ApplicationException("Unknown exception");
}
}
}
When I visit: http://localhost:80/MyService.svc/Authenticate/someUserName/somePassword in my browser window, an empty screen appears. I was expecting "false" to appear in JSON syntax. What am I doing wrong?
Thank you!
Use a tool like Fiddler to see the actual HTTP messages. Helps with debugging.
Second, you're request URL is wrong. Try this:
http://localhost:80/MyService.svc/Authenticate/someUserName/somePassword
You do have a SVC file, correct? You'll need that if you're hosting this in IIS. If you're self hosting it in a WebServiceHost object, then you don't need them.
using( WebServiceHost host = new WebServiceHost( typeof( MyService) ) )
{
host.Open();
Console.WriteLine( "Service is running" );
Console.WriteLine( "Press enter to quit..." );
Console.ReadLine();
host.Close();
}

System.UnsupportedException using WCF on Windows Phone 7

Has anyone been able to communicate using WCF on Windows Phone Series 7 emulator?
I've been trying for the past two days and it's just happening for me. I can get a normal Silverlight control to work in both Silverlight 3 and Silverlight 4, but not the phone version. Here are two versions that I've tried:
Version 1 - Using Async Pattern
BasicHttpBinding basicHttpBinding = new BasicHttpBinding();
EndpointAddress endpointAddress = new EndpointAddress("http://localhost/wcf/Authentication.svc");
Wcf.IAuthentication auth1 = new ChannelFactory<Wcf.IAuthentication>(basicHttpBinding, endpointAddress).CreateChannel(endpointAddress);
AsyncCallback callback = (result) =>
{
Action<string> write = (str) =>
{
this.Dispatcher.BeginInvoke(delegate
{
//Display something
});
};
try
{
Wcf.IAuthentication auth = result.AsyncState as Wcf.IAuthentication;
Wcf.AuthenticationResponse response = auth.EndLogin(result);
write(response.Success.ToString());
}
catch (Exception ex)
{
write(ex.Message);
System.Diagnostics.Debug.WriteLine(ex.Message);
}
};
auth1.BeginLogin("user0", "test0", callback, auth1);
This version breaks on this line:
Wcf.IAuthentication auth1 = new ChannelFactory<Wcf.IAuthentication>(basicHttpBinding, endpointAddress).CreateChannel(endpointAddress);
Throwing System.NotSupportedException. The exception is not very descriptive and the callstack is equally not very helpful:
at System.ServiceModel.DiagnosticUtility.ExceptionUtility.BuildMessage(Exception x)
at System.ServiceModel.DiagnosticUtility.ExceptionUtility.LogException(Exception x)
at System.ServiceModel.DiagnosticUtility.ExceptionUtility.ThrowHelperError(Exception e)
at System.ServiceModel.ChannelFactory`1.CreateChannel(EndpointAddress address)
at WindowsPhoneApplication2.MainPage.DoLogin()
....
Version 2 - Blocking WCF call
Here is the version that doesn't use the async pattern.
[System.ServiceModel.ServiceContract]
public interface IAuthentication
{
[System.ServiceModel.OperationContract]
AuthenticationResponse Login(string user, string password);
}
public class WcfClientBase<TChannel> : System.ServiceModel.ClientBase<TChannel> where TChannel : class {
public WcfClientBase(string name, bool streaming)
: base(GetBinding(streaming), GetEndpoint(name)) {
ClientCredentials.UserName.UserName = WcfConfig.UserName;
ClientCredentials.UserName.Password = WcfConfig.Password;
}
public WcfClientBase(string name) : this(name, false) {}
private static System.ServiceModel.Channels.Binding GetBinding(bool streaming) {
System.ServiceModel.BasicHttpBinding binding = new System.ServiceModel.BasicHttpBinding();
binding.MaxReceivedMessageSize = 1073741824;
if(streaming) {
//binding.TransferMode = System.ServiceModel.TransferMode.Streamed;
}
/*if(XXXURLXXX.StartsWith("https")) {
binding.Security.Mode = BasicHttpSecurityMode.Transport;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
}*/
return binding;
}
private static System.ServiceModel.EndpointAddress GetEndpoint(string name) {
return new System.ServiceModel.EndpointAddress(WcfConfig.Endpoint + name + ".svc");
}
protected override TChannel CreateChannel()
{
throw new System.NotImplementedException();
}
}
auth.Login("test0", "password0");
This version crashes in System.ServiceModel.ClientBase<TChannel> constructor. The call stack is a bit different:
at System.Reflection.MethodInfo.get_ReturnParameter()
at System.ServiceModel.Description.ServiceReflector.HasNoDisposableParameters(MethodInfo methodInfo)
at System.ServiceModel.Description.TypeLoader.CreateOperationDescription(ContractDescription contractDescription, MethodInfo methodInfo, MessageDirection direction, ContractReflectionInfo reflectionInfo, ContractDescription declaringContract)
at System.ServiceModel.Description.TypeLoader.CreateOperationDescriptions(ContractDescription contractDescription, ContractReflectionInfo reflectionInfo, Type contractToGetMethodsFrom, ContractDescription declaringContract, MessageDirection direction)
at System.ServiceModel.Description.TypeLoader.CreateContractDescription(ServiceContractAttribute contractAttr, Type contractType, Type serviceType, ContractReflectionInfo& reflectionInfo, Object serviceImplementation)
at System.ServiceModel.Description.TypeLoader.LoadContractDescriptionHelper(Type contractType, Type serviceType, Object serviceImplementation)
at System.ServiceModel.Description.TypeLoader.LoadContractDescription(Type contractType)
at System.ServiceModel.ChannelFactory1.CreateDescription()
at System.ServiceModel.ChannelFactory.InitializeEndpoint(Binding binding, EndpointAddress address)
at System.ServiceModel.ChannelFactory1..ctor(Binding binding, EndpointAddress remoteAddress)
at System.ServiceModel.ClientBase1..ctor(Binding binding, EndpointAddress remoteAddress)
at Wcf.WcfClientBase1..ctor(String name, Boolean streaming)
at Wcf.WcfClientBase`1..ctor(String name)
at Wcf.AuthenticationClient..ctor()
at WindowsPhoneApplication2.MainPage.DoLogin()
...
Any ideas?
As scottmarlowe pointed out, the automagicly generated service refrence just works. I have set upon the mission to work out just why the bloody hell it works and the manual version doesn't.
I found the culprit and it is ChannelFactory. For some reason new ChannelFactory<T>().CreateChannel() just throws an exception. The only solution I found is to provide your own implementation of the channel. This involves:
Override ClientBase. (optional).
Override ClientBase.CreateChannel. (optional).
Subclass ChannelBase with a specific implementation of your WCF interface
Now, ClientBase already provides an instance of the channel factory thru ChannelFactory property. If you simply call CreateChannel off that you would get the same exception. You need to instantiate a channel that you define in step 3 from within CreateChannel.
This is the basic wireframe of how it all looks put together.
[DataContractAttribute]
public partial class AuthenticationResponse {
[DataMemberAttribute]
public bool Success {
get; set;
}
[System.ServiceModel.ServiceContract]
public interface IAuthentication
{
[System.ServiceModel.OperationContract(AsyncPattern = true)]
IAsyncResult BeginLogin(string user, string password, AsyncCallback callback, object state);
AuthenticationResponse EndLogin(IAsyncResult result);
}
public class AuthenticationClient : ClientBase<IAuthentication>, IAuthentication {
public AuthenticationClient(System.ServiceModel.Channels.Binding b, EndpointAddress ea):base(b,ea)
{
}
public IAsyncResult BeginLogin(string user, string password, AsyncCallback callback, object asyncState)
{
return base.Channel.BeginLogin(user, password, callback, asyncState);
}
public AuthenticationResponse EndLogin(IAsyncResult result)
{
return Channel.EndLogin(result: result);
}
protected override IAuthentication CreateChannel()
{
return new AuthenticationChannel(this);
}
private class AuthenticationChannel : ChannelBase<IAuthentication>, IAuthentication
{
public AuthenticationChannel(System.ServiceModel.ClientBase<IAuthentication> client)
: base(client)
{
}
public System.IAsyncResult BeginLogin(string user, string password, System.AsyncCallback callback, object asyncState)
{
object[] _args = new object[2];
_args[0] = user;
_args[1] = password;
System.IAsyncResult _result = base.BeginInvoke("Login", _args, callback, asyncState);
return _result;
}
public AuthenticationResponse EndLogin(System.IAsyncResult result)
{
object[] _args = new object[0];
AuthenticationResponse _result = ((AuthenticationResponse)(base.EndInvoke("Login", _args, result)));
return _result;
}
}
}
TLDR; If you want to use your own WCF code on WP7 you need to create your own channel class and not rely on ChannelFactory.
Dynamic proxy creation using ChannelFactory.CreateChannel() is not supported on Windows Phone. This is documented here - http://msdn.microsoft.com/en-us/library/ff426930(VS.96).aspx
Consuming a service using the 'Add service reference' mechanism in a async pattern would be the correct way to do.
I put a blog post together on this very subject: http://blogs.msdn.com/b/andypennell/archive/2010/09/20/using-wcf-on-windows-phone-7-walk-through.aspx
I haven't had any problems, but I went the "add service reference..." route which I had to do via "VS2010 Express for Windows Phone" b/c VS2010 RC doesn't yet support that feature for WP7 development. The Express version comes with the WP7 Developer's install.