How do i call WCF services in Silverlight? - silverlight

Can anybody tell me why is this not working. I have created a WCF service which returns a list of customers from Northwind database.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.ServiceModel.Activation;
namespace WCFSilverlight.Web
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Customers" in code, svc and config file together.
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class Customers : ICustomers
{
IEnumerable<Customer> ICustomers.GetAllCustomers()
{
NorthwindEntities objNorthwindEntities = new NorthwindEntities();
var query = from cust in objNorthwindEntities.Customers
select cust;
return query.ToList();
}
}
}
And this is my App.xaml.cs code fragment :-
private void Application_Startup(object sender, StartupEventArgs e)
{
this.RootVisual = new MainPage();
CustomersClient objCustomersClient = new CustomersClient();
objCustomersClient.GetAllCustomersCompleted += new EventHandler<GetAllCustomersCompletedEventArgs>(client_GetNameCompleted);
objCustomersClient.GetAllCustomersAsync();
}
void client_GetNameCompleted(object sender, GetAllCustomersCompletedEventArgs e)
{
MessageBox.Show(e.Result.ToString());
}
If I am not wrong the methods in Silverlight are called asynchronously. So I have added a event handler to handle it and then called the method to retrieve customers. But I don't get anything in Messagebox. Further when I try to keep a breakpoint on client_GetNameCompleted, it never executes. But if I keep it in Application_Startup it does execute. What can be the problem?
Also explain me am I doing it correct? I've seen one example where one person directly defines the function using some strange symbols like =>.
EDIT 1:- Kindly also explain me what is e.UserState in e. What does it contain and what can I possibly do with it?
EDIT 2 :- :- I get this error http://img178.imageshack.us/img178/9070/53923202.jpg
The WCF service is working perfectly i have tested the link query. So there is no problem with Sql Server connection or WCF. Something is wrong with my client only.
This is my ServiceReference.ClientConfig :-
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_ICustomers" maxBufferSize="2147483647"
maxReceivedMessageSize="2147483647">
<security mode="None" />
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:50622/Customers.svc" binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_ICustomers" contract="CustomerServ.ICustomers"
name="BasicHttpBinding_ICustomers" />
</client>
</system.serviceModel>
</configuration>
Can you now tell me what is wrong?
Thanks in advance :)
Update :- I read in google you need to set serialization mode to unidirectional. But where do i set this? What do i write where?

You are correct, All network calls in Silverlight are done asynchronously.
The => syntax you mention is shorthand for defining a delegate method, its called a lambda. (see below)
You should be able to set a break-point in the Completed event handler, if not try restarting Visual Studio (I've seen it act strangly before).
e.UserState will have a reference to whatever object you put in the UserState variable for the async call (note the extra overload).
Code:
objCustomersClient.GetAllCustomersCompleted = delegate(object Sender, GetAllCustomersCompletedEventArgs e)
{
MessageBox.Show(e.Result.ToString());
};
// is the same as
objCustomersClient.GetAllCustomersCompleted += new EventHandler<GetAllCustomersCompletedEventArgs>(client_GetNameCompleted);
void client_GetNameCompleted(object sender, GetAllCustomersCompletedEventArgs e)
{
MessageBox.Show(e.Result.ToString());
}
// which is same as
objCustomersClient.GetAllCustomersCompleted += (sender, e) => { MessageBox.Show(e.Result.ToString()); };

Related

Thread.CurrentThread.CurrentUICulture changes .net 4.8 when async is used

I started to use async operations in my WPF application and realized that Buttons, Labels are on the correct culture (hu-HU), but MessageBox.Show works on the culture of the operating system (en-US). I have resource files for both languages.
App.OnStartup contains
Thread.CurrentThread.CurrentCulture = new CultureInfo("hu-HU");
Thread.CurrentThread.CurrentUICulture = new CultureInfo("hu-HU");
When I press a button in my application and go to the VM I see that Thread.CurrentThread.CurrentUICulture is changed to "en-US" (Thread.CurrentThread.CurrentCulture remained "hu-HU"). I understand this was an issue before .net 4.6 (https://stackoverflow.com/a/30664385/5852947) but it should not be in 4.8. As I understand https://learn.microsoft.com/en-us/dotnet/api/system.globalization.cultureinfo?view=netcore-3.1#Async states the both culture should be inherited from the originating thread.
I also tried this without success.
CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("hu-HU");
CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo("hu-HU");
UPDATE 1
I have a WPF application and I set the culture in OnStartup(). The culture is not hard coded I just wanted to simplify the code.
On the image you can see that the gui is in Hungarian but when I press a button and the corresponding ICommand run in the VM then CurrentUICulture is not correct. In debug mode at the execution of ICommand I also see that CurrentUICulture is not correct. I only set the culture in App.OnStartup. I had no problem until I did not use async. I changed OnStartup() to async because at one point it contains await.
protected async override void OnStartup(StartupEventArgs startupEventArgs)
{
base.OnStartup(startupEventArgs);
var cultureString = ConfigurationManager.AppSettings["Language"];
Thread.CurrentThread.CurrentCulture = new CultureInfo(cultureString);
Thread.CurrentThread.CurrentUICulture = new CultureInfo(cultureString);
CultureInfo.DefaultThreadCurrentCulture = new CultureInfo(cultureString);
CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo(cultureString);
var mainWindowView = new MainWindowView();
// ...
mainWindowView.Show();
ScrollDownInTableTab(mainWindowViewModel);
}
Calling Wait() on a task blocks and potentially also deadlocks. Don't do this. A task represents an asynchronous operation that should be awaited.
As for the issue with culture, you can switch back to the old behaviour by setting the NoAsyncCurrentCulture switch to true in your App.config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8"/>
</startup>
<runtime>
<AppContextSwitchOverrides value="Switch.System.Globalization.NoAsyncCurrentCulture=true"/>
</runtime>
</configuration>

it seems that service method are not really called asynchronously

Regarding my previous post: 910220 - service methods run dependently
since the code and what I meant about the problem I had with it was a bit complex, I come again with a completely changed code which explains itself better.
In client side, we have:
#define USE_ONLY_ONE_INSTANCE
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using CountTester.ServiceReference1;
namespace CountTester
{
public partial class MainPage : UserControl
{
#if USE_ONLY_ONE_INSTANCE
private readonly Service1Client _sc = new Service1Client();
#endif
public MainPage()
{
InitializeComponent();
#if USE_ONLY_ONE_INSTANCE
_sc.CountCompleted += OnCountCompleted;
#endif
}
void OnCountCompleted(object sender, AsyncCompletedEventArgs e)
{
if (e.Error != null)
throw new Exception(string.Format("Count Error {0}", e.Error));
}
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
for (int i = 0; i < 100; i++)
{
#if USE_ONLY_ONE_INSTANCE
_sc.CountAsync(i);
#else
var sc = new Service1Client();
sc.CountCompleted += OnCountCompleted;
sc.CountAsync(i);
//sc.CloseAsync();
#endif
}
}
}
}
this is code behind of the XAML. In the code I call a service method 100 times. I tried both cases and get exception in both cases:
case 1: I use only one instance of the proxy for all communications with server.
case 2: I use an instance for each communication with server.
Let's see the code at server before more description:
using System.IO;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.Text;
using System.Threading;
namespace CountTester.Web
{
[ServiceContract(Namespace = "")]
[SilverlightFaultBehavior]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class Service1
{
const string logFileName = #"h:\CountTester.log";
object _logLock = new object();
void log(string s)
{
lock (_logLock)
{
var streamWriter = new StreamWriter(logFileName, true, Encoding.ASCII);
streamWriter.Write(s);
streamWriter.Close();
}
}
Service1()
{
//File.Delete(logFileName);
}
[OperationContract]
public void Count(int counter)
{
log(string.Format("{0}\n", counter));
Thread.Sleep(3000);
}
}
}
Count is the service method which is called. I deliberately wait 3 seconds in the method. what I expect is that the for at the client get accomplished with no delay. I expect the method gets called asynchronously and this means that first call doesn't affect on the second call.
In another words, if i call the method and it waits to get accomplished, calling it again doesn't get delayed.
While this is the case. how can I figure out that this happens? by using Tail for Windows, I find that the number which is logged is delayed in getting logged. I also figure out this when I see that I get time out exception in response to calling the service method (Count Error...). I hope I could clarify my question.
I also wonder when I see malfunctioning of the program (Exception), when I uncomment the line in which I've closed the service?
Please answer these two questions.
Question 1:
By default your IIS web service will only allow 2 simultaneous requests from the same IP address. This limitation is a default to stop DOS (Denial Of Service) attacks.
That means the subsequent 98 calls are waiting at least 3 seconds, per pair, while the previous ones complete. Eventually you will hit the default 30 second(?) server timeout long before the last requests are processed.
If you insist on running that many simultaneous requests (you shouldn't anyway), you will need to increase the default limits in your web.config file on the server. See my other answer here for more details
Question 2:
You should not close an async call immediately after starting it... the call is still in progress. That code makes no sense.
Notes:
Logging is delayed anyway, for efficiency, so don't use that as a guide.

Caliburn Micro with NLog - how to use logger and log to XML file

Hi i try use Nlog in with caliburn micro, I have use this tutorial http://buksbaum.us/2010/08/08/how-to-do-logging-with-caliburn-micro/.
Firstt I defined Nloagger class, here is it:
public class NLogLogger : ILog
{
#region Fields
private readonly NLog.Logger _innerLogger;
#endregion
#region Constructors
public NLogLogger(Type type)
{
_innerLogger = NLog.LogManager.GetLogger(type.Name);
}
#endregion
#region ILog Members
public void Error(Exception exception)
{
_innerLogger.ErrorException(exception.Message, exception);
}
public void Info(string format, params object[] args)
{
_innerLogger.Info(format, args);
}
public void Warn(string format, params object[] args)
{
_innerLogger.Warn(format, args);
}
#endregion
}
That I modified MEF bootraper:
#region Constructors
public MefBootStrapper()
: base()
{
_msgBox = new MessageBoxes();
_doHandle = true;
}
static MefBootStrapper()
{
LogManager.GetLog = type => new NLogLogger(type);
}
#endregion
and last modified app.config
<?xml version="1.0"?>
<configuration>
<configSections>
<section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog"/>
</configSections>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<targets>
<target name="logfile" xsi:type="File" fileName="file.txt" />
</targets>
<rules>
<logger name="*" minlevel="Error" writeTo="logfile" />
</rules>
</nlog>
</configuration>
It is really stupid for me but I dont know how to use now logger in View model class and second I would like to know if it is possible log with NLog to XML files.
Thank you for support
To use a logger, you need to ask for one. You can do this by requesting a logger instance in the Constructor (explicit) or property (implicit), or even ask the log manager to give it to you.
Here's what you can do in your ViewModel:
public void MyViewModel
{
public MyViewModel()
{
Caliburn.Core.Logging.ILog logger = Caliburn.Core.Logging.LogManager.GetLog(typeof(MyViewModel));
logger.Info("Something Happened");
}
}
Alternatively you can inject a ILog instance (via constructor or property), if you have already registered one in the container you chose with Caliburn. I use Castle Windsor, so the registration part would look like this:
container.Register(Component.For<ILog>().ImplementedBy<NLogLogger>().LifeStyle.Transient);
And you can just ask for a logger in your constructor:
public void MyViewModel
{
public MyViewModel(ILog logger)
{
logger.Info("Something Happened");
}
}
I realize that an answer has been accepted for this question, but I thought that I would mention that your NLog wrapper could be written better. As it is implemented right now, you will not get the correct information if you turn on the logging of callsite information (the class/method making the logging call). Rather than getting the callsite from where you are calling your NLog wrapper, you will get the callsite where the wrapper calls NLog.
Take a look at my answer to the following question for the correct way to write an NLog wrapper (correct in the sense that the callsite information is preserved).
How to retain callsite information when wrapping NLog
The question asks how to write a wrapper for NLog with a particular pattern (his Log method gets the NLog logger and then calls the appropriate Info, Warn, Error, etc method). This pattern is a little bit unorthodox (getting the logger during every call). The more typical pattern, which you are doing, is to get the NLog logger in your constructor. See the following link for an example of how to write an NLog wrapper in this pattern that preserves the callsite information:
Nlog Callsite is wrong when wrapper is used
Note that a very similar technique is required if you want to write a wrapper for log4net.
Good luck!

Download a html file in Silverlight

I'm trying to use the WebClient class to download a html file from another website and present it as a text stream, But I'm getting a security error, what am I doing wrong, or is this another one of Silverlights security "Features"
[code]
namespace ImageScrape
{
public partial class Page : UserControl
{
public Page()
{
InitializeComponent();
}
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
WebClient cl = new WebClient();
cl.OpenReadCompleted += new OpenReadCompletedEventHandler(cl_OpenReadCompleted);
cl.OpenReadAsync(new Uri(#"http://www.google.co.uk/",UriKind.Absolute));
}
void cl_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
testTextBlock.Text = e.Result.ToString();
}
}
}
[/code]
EDIT
Thanks guys, I was really hoping I wouldn't have to create this as a WCF service as 1) I only know the basics and 2) The idea is that you can use this .xap without having to connect to a central server, mainly because for this I don't have a server that I could host a WCF service on.
Does anyone know a way to get around this, or anywhere that would host a WCF service for free?
I think there are security issues with going directly to another site from the silverlight client.
The best work around for this would be to move this code into a web service and then serve the content you require to client from there.

WPF - How do i insert my proxy credentials in WebBrowser Control

I'm using a webbrowser control in WPF to show a virtual earth map, but because I'm developing behind a proxy of my company, every time I try to see the map, I have to insert my credentials.
I would like to insert them automatically in the c# code, how can I achieve that?
I already try in the navigating event of the web browser using:
void webBrowser_Navigating(object sender, NavigatingCancelEventArgs e)
{
//NetworkCredential credential = new NetworkCredential("u007239", "****", "****");
//e.WebRequest.Proxy.Credentials = credential;
}
But this doesn't work because I'm getting that e.webrequest is a null object.
all the help is welcome.
Can you not just put the following in your app.config?
<configuration>
<system.net>
<defaultProxy useDefaultCredentials="true" enabled="true"></defaultProxy>
</system.net>
</configuration>

Resources