Below is a segment of code from a client handler class.
I know I am passing the wrong information as noted in the comment below. I just need to know exactly what I should pass to make it work.
public static void add2ClientList(string s)
{
MainWindow.mainWindow.ClientListBox.Items.Add(s);
}
Action<string> addToClientListBox = new Action<string> (add2ClientList);
public void addClientToPool(Client c)
{
if (ClientPool == null)
{
ClientPool = new Client[] { c };
uiDispatcher.BeginInvoke(addToClientListBox, DispatcherPriority.Background, CancellationToken.None, TimeSpan.Zero, c.getClientIp());
// above is the issue apparently I am passing the wrong params
return;
}
List<Client> temp = new List<Client>();
foreach (Client cc in ClientPool)
{
temp.Add(cc);
}
temp.Add(c);
ClientPool = temp.ToArray();
uiDispatcher.BeginInvoke(addToClientListBox, DispatcherPriority.Background, CancellationToken.None, TimeSpan.Zero, c.getClientIp());
}
The only thing that appears to be missing is your param to pass to the delegate, I assume you want the following:
uiDispatcher.CurrentDispatcher.BeginInvoke(addToClientListBox, new object[]{"ParamString"}, DispatcherPriority.Background);
If that's not exactly what you were asking let me know :)
Delegate d = (Action<string>)add2ClientList;
uiDispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Background, d, c.getClientIp());
Related
So I'm working in Silverlight right now unfortunately for the first time. I'm decently familiar with callbacks, but I'm not entirely sure how to convert this method to be synchronous to perform logic on the order data.
I've been frequently told that making this synchronous was ill-advised, but my goal is to check if certain fields have been modified in the XAML UI and are different from what exists in the database. Then prompt for a reason for the change. If there is a better way to go about this, I'd love to know.
I'm in Silverlight 5 with .Net Framework 4.0 in VS 2013
Thank you! Here's the async order provider:
public void GetOrder(string ordNumber, Action<Func<OrderLoadResults>> callback)
{
String exStr = String.Format("{0}.{1}() --> received an empty value for",
this.GetType().Name,
MethodBase.GetCurrentMethod().Name);
if (ordNumber == null)
{
throw new ArgumentNullException("ordNumber", exStr);
}
if (callback == null)
{
throw new ArgumentNullException("callback", exStr);
}
IOrderServiceAsync channel = CreateChannel();
AsyncCallback asyncCallback = ar => GetOrderCallback(callback, ar);
channel.BeginGetOrderByOrdNumber(ordNumber, asyncCallback.ThreadSafe(), channel);
}
And here's what I'm doing with it:
public List<ATMModifiedFieldModel> CheckForATMModifiedFields()
{
if (!_order.Stops.Items.Any(x => x.ModelState == ModelState.Modified))
{
return null;
}
List<StopModel> oldStop = new List<StopModel>();
Provider.OrderProvider orderProvider = new Provider.OrderProvider();
//Looking to convert this method to sync to pull the order info out to compare against
//orderProvider.GetOrder(_order.Item.OrdHdrNumber.ToString(),getResult => OnGetOrderComplete(getResult));
List<ATMModifiedFieldModel> modifiedFields = new List<ATMModifiedFieldModel>();
foreach (StopModel stop in _order.Stops.Items)
{
if (stop.ModelState == ModelState.Modified)
{
foreach (string ATMFieldName in Enum.GetNames(typeof(ATMFields)))
{
string beforeValue = "before value"; //Should check the value in the database
string afterValue = stop.GetType().GetProperty(ATMFieldName).GetValue(stop, null).ToString();
if (beforeValue != afterValue)
{
modifiedFields.Add(new ATMModifiedFieldModel(ATMFieldName, beforeValue, afterValue, stop.StpNumber, "Stop"));
}
}
}
}
return modifiedFields;
}
I was playing with wcf facility and trying to setup DataContractResolver but I couldn't find any example...
In the end I make it work .. not sure this is ok though ..
Questions
(code below) Is this the right way to accomplish behavior configuration or I am misunderstanding something?
also .. I had to disable async to make it work.. is it a library bug/issue?
Others nice to have before research ..
I was really thinking about performance impact of wcf facility interceptions.. vs benefits of use it. any thoughts?
why is this library not updated any more, (http://docs.castleproject.org/Windsor.AllPages.aspx?Cat=Windsor.WCF-Facility) my concern is regarded using a library that is not longer under maintenance?
var contractdesc = ContractDescription.GetContract(typeof(T));
if (dcr != null)
{
foreach (var operation in contractdesc.Operations)
{
operation.Behaviors.Find<DataContractSerializerOperationBehavior>().DataContractResolver = dcr;
}
}
var myEndpoint = WcfEndpoint.FromEndpoint(
new System.ServiceModel.Description.ServiceEndpoint(
contractdesc
, binding, new EndpointAddress(Url)));
var clientModel = new DefaultClientModel { Endpoint = myEndpoint };
clientModel.WithoutAsyncCapability();
container
.Register(
Types
.From(typeof(T))
.InSameNamespaceAs<T>()
.If(m => m.IsInterface)
.Configure(
c => c.Named(c.Implementation.Name)
.AsWcfClient(
clientModel
).Interceptors(typeof(CastleServiceInterceptor))
),
Component.For<CastleServiceInterceptor>()
);
So i realized (debugging wcf facility) that if WantsAsyncCapability= true the DefaultClientModel is not copying all ServiceEndpoint behaviors, just endpoint behaviors (true is de fault configuration) so here ..
public override ChannelFactory CreateChannelFactory(Type channelFactoryType, M clientModel,
params object[] constructorArgs)
{
if (!clientModel.WantsAsyncCapability)
{
return base.CreateChannelFactory(channelFactoryType, clientModel, constructorArgs);
}
EnsureValidChannelFactoryType(channelFactoryType);
ReplaceServiceEndpointAsyncContracts(constructorArgs);
var interceptor = new CreateDescriptionInterceptor();
var proxyOptions = new ProxyGenerationOptions(asyncChannelFactoryProxyHook);
return (ChannelFactory)generator.CreateClassProxy(
channelFactoryType, Type.EmptyTypes, proxyOptions, constructorArgs, interceptor);
}
Then in ReplaceServiceEndpointAsyncContracts is recreating ServiceEndpoint
private static void ReplaceServiceEndpointAsyncContracts(object[] constructorArgs)
{
for (int i = 0; i < constructorArgs.Length; ++i)
{
var endpoint = constructorArgs[i] as ServiceEndpoint;
if (endpoint != null)
{
var asyncEndpoint = new ServiceEndpoint(ContractDescription.GetContract(
AsyncType.GetAsyncType(endpoint.Contract.ContractType)))
{
Name = endpoint.Name,
Address = endpoint.Address,
Binding = endpoint.Binding,
ListenUri = endpoint.ListenUri,
ListenUriMode = endpoint.ListenUriMode
};
asyncEndpoint.Behaviors.Clear();
foreach (var behavior in endpoint.Behaviors)
{
asyncEndpoint.Behaviors.Add(behavior);
}
constructorArgs[i] = asyncEndpoint;
}
}
}
Above can be seen that not contracto or operation behavior is copied.
So thats it, thanks.
I've search on stackoverflow and also in net and I couldn't find solution to my problem.
I read from a stream in async way. I want callback to update gui
[STAThread]
private void ClientLoggedCallback(IAsyncResult res)
{
try
{
MailClient.Helpers.Client.getInstance().client.GetStream().EndWrite(res);
MailClient.Helpers.Client.getInstance().asyncRecieveEncryptedProtocolMessage(new AsyncCallback(LoginInfo_recieved));
}
catch { }
}
[STAThread]
private void LoginInfo_recieved(IAsyncResult res)
{
try
{
MailClient.Helpers.Client.getInstance().client.GetStream().EndRead(res);
MailClient.AsyncState state = (MailClient.AsyncState)res.AsyncState;
string answer = Aes.DecryptStringFromBytes_Aes(state.buffer, state.AES_KEY, state.AES_IV);
if (answer.Contains("OK"))
{
string[] answer_params = answer.Split(',');
LoggedUserInfo.USER_ID = Convert.ToInt32(answer_params[1]);
LoggedUserInfo.USER_LOGIN = answer_params[2];
//zalogowano
//this.TargetWindow = new MessageListsWindow();
Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background, new Action(() => this.TargetWindow = new MessageListsWindow()));
//System.Windows.Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new Action(() => this.TargetWindow = new MessageListsWindow()));
}
else
{
//zle dane
System.Windows.MessageBox.Show("Zle dane");
}
}
catch(Exception exep) { }
}
This is declaration of asyncSendEncryptedProtocolMessage
asyncSendEncryptedProtocolMessage(string message, AsyncCallback callBack)
use function
clientStream.BeginWrite(encryptedMessage, 0, encryptedMessage.Length, callBack, st);
when code executes I get exception "The calling thread must be STA, because many UI components require this." I read about "SetApartmentState(ApartmentState.STA);" but I don't know how to apply it to callback. I've also tried with STAThread attribute but it doesn't work. I use MVVM Light framework.
StackTrace
" w System.Windows.Threading.DispatcherObject.VerifyAccess()\r\n w System.Windows.Application.get_MainWindow()\r\n w MailClient.ViewModel.MainWindowModel.LoginInfo_recieved(IAsyncResult res) w c:\\Users\\oem\\Documents\\Visual Studio 2012\\Projects\\MvvmLight3\\MailClient\\ViewModel\\MainWindowModel.cs:wiersz 171"
public static void Dispatch(this DispatcherObject source, Action func)
{
if (source.Dispatcher.CheckAccess())
func();
else
source.Dispatcher.Invoke(func);
}
And then use it like this:
MailClient.Helpers.Client.getInstance()
.asyncRecieveEncryptedProtocolMessage(new AsyncCallback(()=>
Application.Current.MainWindow.Dispatch(LoginInfo_recieved)));
I would like to ask is this code thread safe? There is a problem with attachment object. It is passed by reference to the new thread where MailHelper use it and sometimes the attachment object is mixed between threads.
public static void Start()
{
foreach (var message in messages)
{
//skip code
var fileName = httpWebResponse.GetResponseHeader("filename");
var fileStream = httpWebResponse.GetResponseStream();
var attachment = new Attachment(fileStream, fileName);
var thread = new Thread(() =>
{
var dictionary = new ListDictionary
{
{ "$Url$", message.Url }
};
MailHelper.SendMessage(dictionary,
message.Mail.Headers.From.Address,
"EmailConvertSuccess.txt",
attachment)
});
thread.Start();
}
}
No this will probably not be working - but it's not only the attachment (see Darins answer) but the message object you use as an iterator as well - you will have to copy it to a local instance before calling your Thread like this:
var messageCopy = message;
new Thread(a =>
MailHelper.SendMessage(
new ListDictionary { { "$Url$", messageCopy .Url } },
messageCopy.Mail.Headers.From.Address,
"EmailConvertSuccess.txt",
a as MailAttachment)
).Start(attachment);
If you really want to you could pass this as parameter - just like Darin did with it's variant but I don't think this is really needed)
I don't see a problem with attachment. True, it's captured in a closure, but as it's declared inside the loop, there should not be any problem with that.
However, there is a problem with message. Try var message1 = message; and then use message1 in the lambda.
In a normal loop you can break out of a loop using break. Can the same be done using an anonymous delegate?
Example
inputString and result are both declared outside the delegate.
blackList.ForEach(new Action<string>(
delegate(string item)
{
if(inputString.Contains(item)==true)
{
result = true;
// I want to break here
}
}
));
Edit:
Thanks for the replies, I'm actually reading your book at the minute John :) Just for the record i hit this issue and switched back to a normal foreach loop but I posted this question to see if i missed something.
As others have posted, you can't exit the loop in ForEach.
Are you able to use LINQ? If so, you could easily combine TakeWhile and a custom ForEach extension method (which just about every project seems to have these days).
In your example, however, List<T>.FindIndex would be the best alternative - but if you're not actually doing that, please post an example of what you really want to do.
There is no loop that one has access to, from which to break. And each call to the (anonymous) delegate is a new function call so local variables will not help. But since C# gives you a closure, you can set a flag and then do nothing in further calls:
bool stop = false;
myList.ForEach((a) => {
if (stop) {
return;
} else if (a.SomeCondition()) {
stop = true;
}
});
(This needs to be tested to check if correct reference semantics for closure is generated.)
A more advanced approach would be to create your own extension method that allowed the delegate to return false to stop the loop:
static class MyExtensions {
static void ForEachStoppable<T>(this IEnumerable<T> input, Func<T, bool> action) {
foreach (T t in input) {
if (!action(t)) {
break;
}
}
}
}
Do you have LINQ available to you? Your logic seems similar to Any:
bool any = blackList.Any(s=>inputString.Contains(s));
which is the same as:
bool any = blackList.Any(inputString.Contains);
If you don't have LINQ, then this is still the same as:
bool any = blackList.Find(inputString.Contains) != null;
If you want to run additional logic, there are things you can do (with LINQ) with TakeWhile etc
I don't think there's an elegant way to do it when using the ForEach method. A hacky solution is to throw an exception.
What's preventing you from doing an old fashioned foreach?
foreach (string item in blackList)
{
if (!inputString.Contains(item)) continue;
result = true;
break;
}
If you want a loop, use a loop.
Action allows for no return value, so there's no way the ForEach function could possibly know that you want to break, short of throwing an exception. Using an exception here is overkill.
The only way to "exit" the loop is to throw an exception. There is no "break" style way of exiting the .ForEach method like you would a normal foreach loop.
The ForEach method is not mean to do this. If you want to know if a collection contains an item you should use the Contains method. And if you want to perform a check on all items in a collection you should try the Any extention method.
bool #break = false;
blackList.ForEach(item =>
{
if(!#break && inputString.Contains(item))
{ #break = true;
result = true;
}
if (#break) return;
/* ... */
});
Note that the above will still iterate through each item but return immediately. Of course, this way is probably not as good as a normal foreach.
class Program
{
static void Main(string[] args)
{
List<string> blackList = new List<string>(new[] { "jaime", "jhon", "febres", "velez" });
string inputString = "febres";
bool result = false;
blackList.ForEach((item) =>
{
Console.WriteLine("Executing");
if (inputString.Contains(item))
{
result = true;
Console.WriteLine("Founded!");
}
},
() => result);
Console.WriteLine(result);
Console.ReadLine();
}
}
public static class MyExtensions
{
public static void ForEach<T>(this IEnumerable<T> enumerable, Action<T> action, Func<bool> breakOn)
{
foreach (var item in enumerable)
{
action(item);
if (breakOn())
{
break;
}
}
}
}
Would this work for you:
bool result = null != blackList.Find( item => inputString.Contains(item)) );
blackList.ForEach(new Action<string>(
delegate(string item)
{
if(inputString.Contains(item)==true)
{
result = true;
// I want to break here
return;
}
}
));
if you realy want to exist a loop foreach in a list you could use the exception like this code:
public class ExitMyForEachListException : Exception
{
public ExitMyForEachListException(string message)
: base(message)
{
}
}
class Program
{
static void Main(string[] args)
{
List<string> str = new List<string>() { "Name1", "name2", "name3", "name4", "name5", "name6", "name7" };
try
{
str.ForEach(z =>
{
if (z.EndsWith("6"))
throw new ExitMyForEachListException("I get Out because I found name number 6!");
System.Console.WriteLine(z);
});
}
catch (ExitMyForEachListException ex)
{
System.Console.WriteLine(ex.Message);
}
System.Console.Read();
}
}
hope this help to get other point of view.