Trying to perform a number of HTTP Get requests in parallel, one per task. If I do the Gets through internet explorer they return almost instantaneously, but when calling in code through tasks, the first time I fire them off they take a good few seconds to return, but running a second time they return as I would expect. So either I'm doing something which is blocking something, or for some reason the threads are not starting? It's my first time trying to use TPL.
Here's the basic lookup class:
public class Lookup
{
public string Name { get; set; }
public string URL { get; set; }
public Lookup(string Name, string URL)
{
this.Name = Name;
this.URL = URL;
}
public LookupReturn DoLookup()
{
LookupReturn d = new LookupReturn();
d.Name = this.Name;
d.URL = this.URL;
WebRequest wrGETURL;
wrGETURL = WebRequest.Create(this.URL);
Stream objStream;
objStream = wrGETURL.GetResponse().GetResponseStream();
StreamReader objReader = new StreamReader(objStream);
string sLine = objReader.ReadToEnd();
d.Result = sLine;
return d;
}
}
And the return type is simply:
public class LookupReturn
{
public string Name { get; set; }
public string Result { get; set; }
public string URL { get; set; }
}
So the attempt to run this in parallel - am testing from a Winforms GUI but eventually will be in a WCF service.
public partial class Form1 : Form
{
private List<Lookup> Lookups = new List<Lookup>();
private async void btnRunLookups_Click(object sender, EventArgs e)
{
Lookups.Add(new Lookup("Name1", "http://geturl1 "));
Lookups.Add(new Lookup("Name2", "http://geturl2 "));
// More lookups…
int workerThreads, complete;
ThreadPool.GetMinThreads(out workerThreads, out complete);
ThreadPool.SetMinThreads(100, complete);
btnRunLookups.Visible = false;
List <Task<LookupReturn>> lookupTasks = new List<Task<LookupReturn>>();
foreach(Lookup dl in Lookups)
{
lbLookups.Items.Add("Starting task for " + dl.URL);
Task<LookupReturn> t = new Task<LookupReturn>(() => dl.DoLookup() );
lookupTasks.Add(t);
t.Start();
}
//await Task.WhenAny(
// Task.WhenAll(lookupTasks.ToArray<Task<LookupReturn>>()),
// Task.Delay(3000)
// );
// This takes a good few seconds the first time
await Task.WhenAll(lookupTasks.ToArray<Task<LookupReturn>>());
// Now I need to see which ones completed and returned a result
foreach (var x in lookupTasks)
{
if (x.IsCompleted)
{
lbLookups.Items.Add(x.Result);
}
else
{
// lbLookups.Items.Add("Not finished " + x.Result.Name);
}
}
btnRunLookups.Visible = true;
}
Other people have noted that HttpWebRequest can take a long time on its first request because it's looking for proxy information. Try setting its Proxy property to null.
wrGETURL = WebRequest.Create(this.URL);
wrGETURL.Proxy = null;
Most likely the problem is that the program is doing some first-time setup stuff (DNS resolution, proxy detection, etc.) on the first call to GetResponse. The proxy detection, in particular, can take a good long while.
I'm working on a custom dialog in my WPF application that will allow the user to select a folder anywhere in the network that the user can see. I'm using code that I adapted from this CodeProject article on enumerating network resources.
The code in the original article immediately enumerates all network resources as soon as the EnumerateServers object is instantiated, recursively calling itself whenever it finds a container, and adds each node found to an ArrayList. This is inefficient as:
You can't start enumerating anything until after the network tree has been fully traversed.
The enumeration can take a significant amount of time depending on network traffic & the number of nodes that the current user can see.
I'm displaying the network resources in a WPF TreeView control, so I only want to traverse the nodes that are the direct children of the node that the user has expanded.
With that in mind, I made some changes to the code. Specifically, I modified it so it throws exceptions when errors occur and removed the recursion. The code now looks like this:
[StructLayout( LayoutKind.Sequential )]
internal class NetResource {
public ResourceScope Scope = 0;
public ResourceType Type = 0;
public ResourceDisplayType DisplayType = 0;
public ResourceUsage Usage = 0;
public string LocalName = null;
public string RemoteName = null;
public string Comment = null;
public string Provider = null;
};
public enum ResourceDisplayType {
Generic,
Domain,
Server,
Share,
File,
Group,
Network,
Root,
ShareAdmin,
Directory,
Tree,
NdsContainer
};
public enum ResourceScope {
Connected = 1,
GlobalNet,
Remembered,
Recent,
Context
};
public enum ResourceType {
Any,
Disk,
Print,
Reserved
};
[Flags]
public enum ResourceUsage {
Connectible = 0x00000001,
Container = 0x00000002,
NoLocalDevice = 0x00000004,
Sibling = 0x00000008,
Attached = 0x00000010,
All = Connectible | Container | Attached,
};
public class Share {
public string Comment { get; private set; }
public ResourceDisplayType DisplayType { get; private set; }
public string Name { get; private set; }
public string Provider { get; private set; }
public ResourceScope Scope { get; private set; }
public ResourceType ShareType { get; private set; }
public ResourceUsage Usage { get; private set; }
public string UNCPath { get; private set; }
internal Share( NetResource netResource ) {
DisplayType = netResource.DisplayType;
Scope = netResource.Scope;
ShareType = netResource.Type;
Usage = netResource.Usage;
if ( !string.IsNullOrWhiteSpace( netResource.Comment ) ) {
char[] commentChars = new char[ netResource.Comment.Length ];
netResource.Comment.CopyTo( 0, commentChars, 0, netResource.Comment.Length );
Comment = new string( commentChars );
}
if ( !string.IsNullOrWhiteSpace( netResource.LocalName ) ) {
char[] localNameChars = new char[ netResource.LocalName.Length ];
netResource.LocalName.CopyTo( 0, localNameChars, 0, netResource.LocalName.Length );
Name = new string( localNameChars );
}
if ( !string.IsNullOrWhiteSpace( netResource.Provider ) ) {
char[] providerChars = new char[ netResource.Provider.Length ];
netResource.Provider.CopyTo( 0, providerChars, 0, netResource.Provider.Length );
Provider = new string( providerChars );
}
if ( !string.IsNullOrWhiteSpace( netResource.RemoteName ) ) {
char[] remoteNameChars = new char[ netResource.RemoteName.Length ];
netResource.RemoteName.CopyTo( 0, remoteNameChars, 0, netResource.RemoteName.Length );
UNCPath = new string( remoteNameChars );
}
}
}
public class ShareEnumerator : IEnumerable<Share> {
public string Comment { get; set; }
public ResourceDisplayType DisplayType { get; set; }
public string Provider { get; set; }
public string ResourceName { get; set; }
public string ResourcePath { get; set; }
public ResourceScope Scope { get; set; }
public ResourceType ShareType { get; set; }
public ResourceUsage Usage { get; set; }
public ShareEnumerator() { }
public ShareEnumerator( Share aShare ) {
Comment = aShare.Comment;
DisplayType = aShare.DisplayType;
Provider = aShare.Provider;
ResourceName = aShare.Name;
ResourcePath = aShare.UNCPath;
Scope = aShare.Scope;
ShareType = aShare.ShareType;
Usage = aShare.Usage;
}
public IEnumerator<Share> GetEnumerator() {
NetResource netResource = new NetResource {
Comment = this.Comment,
DisplayType = this.DisplayType,
LocalName = this.ResourceName,
Provider = this.Provider,
RemoteName = this.ResourcePath,
Scope = this.Scope,
Type = this.ShareType,
Usage = this.Usage
};
uint bufferSize = 16384;
IntPtr buffer = IntPtr.Zero;
uint cEntries = 1;
IntPtr handle = IntPtr.Zero;
ErrorCodes result;
try {
buffer = Marshal.AllocHGlobal( (int) bufferSize );
result = WNetOpenEnum( Scope, ShareType, Usage, netResource, out handle );
if ( result != ErrorCodes.NO_ERROR ) {
throw new InvalidOperationException( string.Format( "The call to WNetOpenEnum failed: the result code was {0:x}", (int) result ) );
}
try {
do {
result = WNetEnumResource( handle, ref cEntries, buffer, ref bufferSize );
if ( result == ErrorCodes.NO_ERROR ) {
// It was. Marshal the buffer into the NetResource object.
Marshal.PtrToStructure( buffer, netResource );
if ( netResource.DisplayType == DisplayType || netResource.DisplayType == ResourceDisplayType.Domain ) {
// We do. Convert it into a Share & enumerate it.
yield return new Share( netResource );
}
} else if ( result == ErrorCodes.ERROR_NO_MORE_ITEMS ) {
break;
} else {
throw new InvalidOperationException( string.Format( "The call to WNetEnumResource failed: the result code was {0:x}", (int) result ) );
}
} while ( result == ErrorCodes.NO_ERROR );
} finally {
WNetCloseEnum( (IntPtr) buffer );
}
} finally {
if ( buffer != IntPtr.Zero ) {
// VERY IMPORTANT! Deallocate the buffer to prevent memory leaks!!
Marshal.FreeHGlobal( buffer );
}
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
return GetEnumerator();
}
private enum ErrorCodes {
NO_ERROR = 0,
ERROR_NO_MORE_ITEMS = 259
};
[DllImport( "Mpr.dll", EntryPoint = "WNetOpenEnumA", CallingConvention = CallingConvention.Winapi )]
private static extern ErrorCodes WNetOpenEnum( ResourceScope dwScope, ResourceType dwType, ResourceUsage dwUsage, NetResource p, out IntPtr lphEnum );
[DllImport( "Mpr.dll", EntryPoint = "WNetCloseEnum", CallingConvention = CallingConvention.Winapi )]
private static extern ErrorCodes WNetCloseEnum( IntPtr hEnum );
[DllImport( "Mpr.dll", EntryPoint = "WNetEnumResourceA", CallingConvention = CallingConvention.Winapi )]
private static extern ErrorCodes WNetEnumResource( IntPtr hEnum, ref uint lpcCount, IntPtr buffer, ref uint lpBufferSize );
}
}
When the user clicks on the "Entire Network" node in the TreeView for a network node, this code runs:
private void NetworkExpanded( object sender, RoutedEventArgs e ) {
if ( !ShareScanner.IsBusy ) {
OriginalCursor = LayoutRoot.Cursor;
LayoutRoot.Cursor = Mouse.OverrideCursor = Cursors.Wait;
TreeViewItem networkItem = sender as TreeViewItem;
if ( networkItem.Items.Count == 1 && networkItem.Items[ 0 ] == dummyNode ) {
networkItem.Items.Clear();
ShareScanner.RunWorkerAsync( new ShareScannerArgs( networkItem, networkItem.Tag as Share, ShareScannerTypes.Computers ) );
}
}
e.Handled = true;
}
Underneath the Entire Network node will be nodes for specific computers that the user can see. When they expand one of these nodes, this code is run:
private void NetworkComputerExpanded( object sender, RoutedEventArgs e ) {
if ( !ShareScanner.IsBusy ) {
OriginalCursor = LayoutRoot.Cursor;
LayoutRoot.Cursor = Mouse.OverrideCursor = Cursors.Wait;
TreeViewItem computerItem = sender as TreeViewItem;
if ( computerItem.Items.Count == 1 && computerItem.Items[ 0 ] == dummyNode ) {
computerItem.Items.Clear();
ShareScanner.RunWorkerAsync( new ShareScannerArgs( computerItem, computerItem.Tag as Share, ShareScannerTypes.Shares ) );
}
}
e.Handled = true;
}
Below the computer nodes there will be "Share" nodes. When they click on a "Share" node in the TreeView, this code runs:
private void NetworkShareExpanded( object sender, RoutedEventArgs e ) {
if ( !ShareScanner.IsBusy ) {
OriginalCursor = LayoutRoot.Cursor;
LayoutRoot.Cursor = Mouse.OverrideCursor = Cursors.Wait;
TreeViewItem shareItem = sender as TreeViewItem;
if ( shareItem.Items.Count == 1 && shareItem.Items[ 0 ] == dummyNode ) {
shareItem.Items.Clear();
ShareScanner.RunWorkerAsync( new ShareScannerArgs( shareItem, shareItem.Tag as Share, ShareScannerTypes.Folders ) );
}
}
e.Handled = true;
}
There will be nodes for individual folders below the shares, but I haven't written any code for that level yet as I'm trying to get the other levels to work.
As you can see from the code I've posted, I'm using a BackgroundWorker to actually do the work. The UI becomes unresponsive while the calls to WNetOpenEnum and WNetEnumResource execute. My UI has to remain responsive, so I use the BackgroundWorker to do the waiting & keep the UI responsive.
Here's the BackgroundWorker's DoWork event handler:
private void ShareScanner_DoWork( object sender, DoWorkEventArgs e ) {
BackgroundWorker worker = sender as BackgroundWorker;
ShareScannerArgs info = e.Argument as ShareScannerArgs;
ShareEnumerator enumerator = null;
switch ( info.WhatToScanFor ) {
case ShareScannerTypes.Computers:
enumerator = new ShareEnumerator {
DisplayType = ResourceDisplayType.Network, // Retrieve Servers only
Scope = ResourceScope.GlobalNet, // Retrieve only objects the user can see
ShareType = ResourceType.Disk, // Retrieve only Disk shares
Usage = ResourceUsage.All // Retrieve all Connectible, Container & Attached nodes.
};
break;
case ShareScannerTypes.Shares:
case ShareScannerTypes.Folders:
enumerator = new ShareEnumerator( info.ParentShare );
break;
default:
// Should never get here!
throw new InvalidOperationException( string.Format( "Unknown ShareScannerType: {0}", info.WhatToScanFor ) );
}
try {
foreach ( Share share in enumerator ) {
if ( worker.CancellationPending ) {
e.Cancel = true;
return;
}
worker.ReportProgress( 0, new NodeArgs( info.Parent, share, info.WhatToScanFor ) );
}
} catch ( Exception ) { }
}
Here's the code for the ProgressChanged event handler:
private void ShareScanner_ProgressChanged( object sender, ProgressChangedEventArgs e ) {
NodeArgs nodeArgs = e.UserState as NodeArgs;
Share parentShare = nodeArgs.Tag as Share;
TreeViewItem item = new TreeViewItem {
Header = parentShare.UNCPath,
Tag = nodeArgs.Tag
};
switch ( nodeArgs.NodeToBuild ) {
case ShareScannerTypes.Computers:
item.Items.Add( dummyNode );
item.Expanded += new RoutedEventHandler( NetworkComputerExpanded );
break;
case ShareScannerTypes.Shares:
item.Items.Add( dummyNode );
item.Expanded += new RoutedEventHandler( NetworkShareExpanded );
break;
case ShareScannerTypes.Folders:
break;
default:
// Should never get here!
throw new InvalidOperationException( string.Format( "Unknown ShareScannerType: : {0}", nodeArgs.NodeToBuild ) );
}
nodeArgs.Parent.Items.Add( item );
}
Finally, the code for the RunWorkerCompleted event:
private void ShareScanner_RunWorkerCompleted( object sender, RunWorkerCompletedEventArgs e ) {
Mouse.OverrideCursor = null;
LayoutRoot.Cursor = OriginalCursor;
}
The code produces a tree with the 'Entire Network' node. When you expand it, I get entries for "Microsoft Terminal Services", "Microsoft Windows Network", and "Web Client Network". When I expand any of these, WNetOpenEnum fails, returning 57 as the result.
What am I doing wrong? The code looked pretty straight forward but obviously I've missed something.
I finally got my dialog working as I wanted, but not using any of the code posted in the original question. Instead, I replaced all of that code with code taken from two other articles on CodeProject. Here are the comments from the code in my application with the information about where the code came from:
The `ComputerEnumerator` class originated as the `NetworkBrowser.cs` class from the
"Retrieving a List of Network Computer Names Using C#" article, which can be found at:
http://www.codeproject.com/Articles/16113/Retreiving-a-list-of-network-computer-names-using
The ShareEnumerator class originated as the ServerEnum.cs class from the
"Network Shares and UNC paths" article, which can be found at:
http://www.codeproject.com/Articles/2939/Network-Shares-and-UNC-paths
The first class makes use of the NetServerEnum function to retrieve all of the computers available on the network, while the second class uses the NetShareEnum method to retrieve the shares available on a particular server. The code from the first article worked correctly as it was. There were a couple of issues with the code in the second article, though.
The biggest problem was in the DllImport for the NetApiBufferFree function. When my code called it in the debugger when I stepped over the call, the function must have errored or something because the debugger never regained control and the code in the method that restored the mouse cursor never ran. When I replaced the definition of that API with the one from the first article, everything worked.
The less serious problem is that the second article created an enum type called ShareType that was decorated with the [Flags] attribute. The problem with this is that the values for the enum are taken from the LMShares.h file and are sequential values, not powers of 2. Such an enum will not work as a set of flags. There should be no enum identifier with the value 3, for example, because that value should be formed by bit-wise ORing the enum values for 1 & 2 together. But the enum identifier for the IPC type, sure enough, is 3.
This problem would (and did) cause problems if you try to use the values in this enum to filter the shares returned. To fix this latter problem, I removed the [Flags] attribute from that type & do not use is with any bit-wise operations.
It is amazing how quickly these functions return values. I'm sure they're cached somewhere and they may take longer to return values in certain circumstances. But in any case I have the code working as I'd like it to work.
When I run my c# console app the windows firewall pops up requesting access for vshost32 (my app listens for incomming messages over port 1234 using TCP and UDP). I accept the offered suggestion (private network). The console app then works fine.
I dont want the user to deal with this, so I have added the code below. However when I investigate what this has done in Control Panel > Firewall, it seems to have enabled it for the 'public network' rather than the private network. This is no use as far as allowing my app to work.
Is there an adjustment in the code below to force it to the private network?
INetFwOpenPorts ports3;
INetFwOpenPort port3 = (INetFwOpenPort)Activator.CreateInstance(
Type.GetTypeFromProgID("HNetCfg.FWOpenPort"));
port3.Port = 1234;
port3.Name = "vshost32.exe";
port3.Enabled = true;
//**UPDATE** added for suggestion in answer below - still doesnt change anything though
port3.Scope = NetFwTypeLib.NET_FW_SCOPE_.NET_FW_SCOPE_LOCAL_SUBNET;
Type NetFwMgrType = Type.GetTypeFromProgID("HNetCfg.FwMgr", false);
INetFwMgr mgr3 = (INetFwMgr)Activator.CreateInstance(NetFwMgrType);
ports3 = (INetFwOpenPorts)mgr3.LocalPolicy.CurrentProfile.GloballyOpenPorts;
ports3.Add(port3);
INetFwRule firewallRule = (INetFwRule)Activator.CreateInstance(
Type.GetTypeFromProgID("HNetCfg.FWRule"));
INetFwPolicy2 firewallPolicy = (INetFwPolicy2)Activator.CreateInstance(
Type.GetTypeFromProgID("HNetCfg.FwPolicy2"));
firewallRule.ApplicationName = "<path to your app>";
firewallRule.Action = NET_FW_ACTION_.NET_FW_ACTION_ALLOW;
firewallRule.Description = " My Windows Firewall Rule";
firewallRule.Enabled = true;
firewallRule.InterfaceTypes = "All";
firewallRule.Name = "<your rule name>";
// Should really check that rule is not already present before add in
firewallPolicy.Rules.Add(firewallRule);
Refer to my answer to your previous question.
Have a look at the following lines:
private static int Main (string [] args)
{
var application = new NetFwAuthorizedApplication()
{
Name = "MyService",
Enabled = true,
RemoteAddresses = "*",
Scope = NET_FW_SCOPE_.NET_FW_SCOPE_ALL,
IpVersion = NET_FW_IP_VERSION_.NET_FW_IP_VERSION_ANY,
ProcessImageFileName = "ServiceAssemblyName.dll",
};
return (FirewallUtilities.AddApplication(application, out exception) ? 0 : -1);
}
The NET_FW_SCOPE_ enumeration has the following values:
NET_FW_SCOPE_ALL = 0,
NET_FW_SCOPE_LOCAL_SUBNET = 1,
NET_FW_SCOPE_CUSTOM = 2,
NET_FW_SCOPE_MAX = 3,
You can further limit the ports, protocol as well as remote addresses to the rule.
UPDATE:
Here is the missing ReleaseComObject function. Place it whatever namespace and remove the reference to ComUtilities.
public static void ReleaseComObject (object o)
{
try
{
if (o != null)
{
if (Marshal.IsComObject(o))
{
Marshal.ReleaseComObject(o);
}
}
}
finally
{
o = null;
}
}
Here is the NetFwAuthorizedApplication class:
namespace MySolution.Configurator.Firewall
{
using System;
using System.Linq;
using NetFwTypeLib;
public sealed class NetFwAuthorizedApplication:
INetFwAuthorizedApplication
{
public string Name { get; set; }
public bool Enabled { get; set; }
public NET_FW_SCOPE_ Scope { get; set; }
public string RemoteAddresses { get; set; }
public string ProcessImageFileName { get; set; }
public NET_FW_IP_VERSION_ IpVersion { get; set; }
public NetFwAuthorizedApplication ()
{
this.Name = "";
this.Enabled = false;
this.RemoteAddresses = "";
this.ProcessImageFileName = "";
this.Scope = NET_FW_SCOPE_.NET_FW_SCOPE_ALL;
this.IpVersion = NET_FW_IP_VERSION_.NET_FW_IP_VERSION_ANY;
}
public NetFwAuthorizedApplication (string name, bool enabled, string remoteAddresses, NET_FW_SCOPE_ scope, NET_FW_IP_VERSION_ ipVersion, string processImageFileName)
{
this.Name = name;
this.Scope = scope;
this.Enabled = enabled;
this.IpVersion = ipVersion;
this.RemoteAddresses = remoteAddresses;
this.ProcessImageFileName = processImageFileName;
}
public static NetFwAuthorizedApplication FromINetFwAuthorizedApplication (INetFwAuthorizedApplication application)
{
return (new NetFwAuthorizedApplication(application.Name, application.Enabled, application.RemoteAddresses, application.Scope, application.IpVersion, application.ProcessImageFileName));
}
}
}
I am developing an app for Windows Phone 8.0 in VS2012
and I have in my SetProfile.xaml Page an IsolatedStorage
SetProfile.xaml
public partial class SetProfile : PhoneApplicationPage
{
private int Indexer;
private int age;
IsolatedStorageSettings Profile = IsolatedStorageSettings.ApplicationSettings;
private void create_Click(object sender, RoutedEventArgs e)
{
if (FirstName.Text != "" && LastName.Text != "" && Age.Text!= "")
{
age = Convert.ToInt32(Age.Text);
//catch (FormatException exc) { };
if (age > 5 || age < 120)
{
Player player = new Player();
player.FirstName = FirstName.Text;
player.LastName = LastName.Text;
try
{
player.Age = Convert.ToInt32(Age.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Age");
Age.Text = "";
return;
}
player.Rank = 1;
player.RankDescreption = "Beginner";
player.Points = 0;
Indexer = GetCurrentIndex();
string key = string.Format("player{0}", Indexer);
if (Indexer == 1)
{
player.ID = Indexer;
Profile.Add("CurrentProfile", player);
Profile.Add("PlayersCount",(int)1);
}
else
Profile["CurrentProfile"] = player;
player.ID = Indexer;
Profile.Add(key, player);
int count = (int)Profile["PlayersCount"];
count++;
Profile["PlayersCount"] = count;
Profile.Save();
NavigationService.Navigate(new Uri("/Avatars.xaml", UriKind.Relative));
}
else
{
MessageBox.Show("Age is Invalid");
create_Click(null, null);
}
}
}
when i debug the app , it crashes on the line Profile.Save();
with 'System.Runtime.Serialization.InvalidDataContractException'
I don't know why it happened , i've been working on my app a long time , and the code was working , but today when i added a class (Game) to the project (related to Player class) , this error started to appear
Further information about the class i added: in this question i posted a little while ago: AccessViolationException while adding item to a list
InvalidDataContractException means that you need to tag what ever you're serializing with the [DataContractAttribute] attribute.
Subsequently you will also need to tag any members of your object with [DataMember] in order for the serializer to recognize it.
Good news, if you want an easier way to serialize objects to the isolated storage I built it already and its free. It's called EZ_iso.dll I have posted about it a number of times on the stack exchange and it has been widely adopted among both new and seasoned devs.
An example would be
[DataContractAttribute]
public class MainPageSettings
{
[DataMember]
publicString yourSetting1 {get; set;}
[DataMember]
public List<Object> yourSetting2 {get; set;}
[DataMember]
public int yourSetting3 {get; set;}
[DataMember]
public Boolean yourSetting4 {get; set;}
}
Now you can save your data and retrieve it with a single line of code
To serialize it (after its been initialized)
EZ_Iso.IsolatedStorageAccess.SaveFile("MPageSettings",yourSettingsObj);
Then to deserialize it
MainPageSettings yourSettingsObj = (MainPageSettings)EZ_Iso.IsolatedStorageAccess.GetFile("MPageSettings",typeof(MainPageSettings));
It's that easy.
You can find it here EZ_Iso
Here's my property that determines if I should bind the other properties or not:
public string LotNumber {
get {
return lotNumber;
}
set {
using (var db = new DDataContext()) {
lotNumber = value;
// Check for duplicates
bool isDuplicate =
db.LotInformation.Any(r => r.lot_number == lotNumber);
if (isDuplicate == true) {
ComponentsList = null;
FamiliesList = null;
ExpirationDate = null;
LotNumber = null;
lotNumber = null;
// Inform user that the lot_number already exists
errorWindow.Message =
LanguageResources.Resource.Lot_Exists_Already;
dialogService.ShowDialog(
LanguageResources.Resource.Error, errorWindow);
logger.writeErrLog(
LanguageResources.Resource.Lot_Exists_Already);
return;
} else {
lotNumber = value;
}
RaisePropertyChanged("LotNumber");
}
}
}
My problem right now is if I upload a file and if the lot number already exists in the database, the boolean returns true and an error message is thrown. However, after that,it loops again and then the boolean is set to false since now the value is null and it still binds the data afterward. How can I break out of the loop and just make it stop running/clear/prevent binding when bool is true in the case above?
I assume you have some code like this:
LotNumber = "ABC5"; // ABC5 already exists in the database - uh oh!
And then you're trying to figure everything out in the "setter". It's already too late by that point. Instead, move your logic into separate methods:
private bool LotNumberExists(string lotNumber)
{
using (var db = new DDataContext())
{
return db.LotInformation.Any(r => r.lot_number == lotNumber);
}
}
private void ClearFields()
{
ComponentsList = null;
FamiliesList = null;
ExpirationDate = null;
LotNumber = null;
}
private void InformUserOfDuplicate()
{
// Inform user that the lot_number already exists
errorWindow.Message = LanguageResources.Resource.Lot_Exists_Already;
dialogService.ShowDialog(LanguageResources.Resource.Error, errorWindow);
logger.writeErrLog(LanguageResources.Resource.Lot_Exists_Already);
}
Then check the return value of that method before setting LotNumber.
private void SomeOtherMethod()
{
string someLotNumber = "ABC5";
if (LotNumberExists(someLotNumber)
{
ClearFields();
InformUserOfDuplicate();
return;
}
LotNumber = someLotNumber;
}
Turn your setter back into a simple setter without a ton of logic wrapped up in it:
public string LotNumber
{
get { return lotNumber; }
set
{
lotNumber = value;
RaisePropertyChanged("LotNumber");
}
}