I'm helping a colleague debug a tool he is creating for ArcGis. It is used to create Replicas, and is done through selecting some different inputs from dropdowns in a winform.
The issue is that when running all the code on the UI-thread, our ui freezes. This is what he wants me to solve. The code causing this is the following, the relevant code is just the button1_Click_1() method, but i provided the second class for contex:
public partial class FrmReplicaAdmin : Form
{
private void button1_Click_1(object sender, EventArgs e)
{
DataConnectionConfig selectedDatabase = cmboxDatabase.SelectedItem as DataConnectionConfig;
if (selectedDatabase.PlWorkspace == null)
{
statusLabel.Text = "Could not open GeoDatabase (PL)";
return;
}
if (selectedDatabase.DataWorkspace == null)
{
statusLabel.Text = "Could not open GeoDatabase (NIS)";
return;
}
int scaleBand = int.Parse(cmboxScale.SelectedItem.ToString());
string gridName = cmboxGridNr.SelectedItem as string;
IGeometry shapeOfSelectedAOI = getSelectedPolygon(gridName, scaleBand, selectedDatabase);
(ArcMap.Application as IMxApplication2).PauseDrawing = true;
replica.CheckOutReplica(selectedDatabase.PlWorkspace, selectedDatabase.DataWorkspace, selectedDatabase.TemplateGdb, gridName, scaleBand, shapeOfSelectedAOI, selectedDatabase.DatasetName);
(ArcMap.Application as IMxApplication2).PauseDrawing = false;
}
}
public class Replica
{
public void CheckOutReplica(IWorkspace plWorkspace, IWorkspace parentWorkspace, string pathToDatabaseTemplate, string gridName, int scaleBand, IGeometry shapeOfSelectedAOI, string datasetName = "NIS.Nautical")
{
try
{
string replicaName = string.Format("{0}_{1}_r", Environment.UserName, gridName);
string versionName = string.Format("{0}_{1}", Environment.UserName, gridName);
string pathToLocalChildDatabase = System.IO.Path.Combine(ReplicationPath, $"{replicaName}.gdb");
Directory.CreateDirectory(pathToLocalChildDatabase);
foreach (string newPath in Directory.GetFiles(pathToDatabaseTemplate, "*.*", SearchOption.AllDirectories))
File.Copy(newPath, newPath.Replace(pathToDatabaseTemplate, pathToLocalChildDatabase), true);
IWorkspace childWorkspace = OpenWorkspace(pathToLocalChildDatabase);
// Create Version in ParentDatabase
IEnumVersionInfo versionEnum = (parentWorkspace as IVersionedWorkspace).Versions;
versionEnum.Reset();
for (IVersionInfo versionInfo = versionEnum.Next(); versionInfo != null; versionInfo = versionEnum.Next())
{
if (versionInfo.VersionName.EndsWith(versionName))
{
System.Windows.Forms.MessageBox.Show("A version named '" + versionName + "' has already been created", "map...", System.Windows.Forms.MessageBoxButtons.OK);
return;
}
}
Marshal.ReleaseComObject(versionEnum);
IVersion newVersion = (parentWorkspace as IVersionedWorkspace).DefaultVersion.CreateVersion(versionName);
newVersion.Access = esriVersionAccess.esriVersionAccessPublic;
string defQuery = "((IS_CONFLATE=1 AND PLTS_COMP_SCALE >= " + scaleBand + ") OR ((IS_CONFLATE=0 OR IS_CONFLATE IS NULL) AND PLTS_COMP_SCALE = " + scaleBand + "))";
ReplicateData(parentWorkspace, newVersion.VersionInfo, replicaName, shapeOfSelectedAOI, childWorkspace, defQuery, datasetName);
// Update map. Show replica data
ILayerFile nauticalLyrFile = new LayerFileClass();
nauticalLyrFile.Open(ReplicationPath + #"\Nautical.lyr");
AddDataToMap((ArcMap.Application.Document as IMxDocument), childWorkspace as IFeatureWorkspace, nauticalLyrFile, gridName, datasetName);
(ArcMap.Application.Document as IMxDocument).ActiveView.Extent = shapeOfSelectedAOI.Envelope;
Marshal.ReleaseComObject(childWorkspace);
}
catch (Exception err)
{
System.Windows.Forms.MessageBox.Show($"Unexpected error. {Environment.NewLine}{err.Message}", "map...", System.Windows.Forms.MessageBoxButtons.OK);
}
}
}
private void ReplicateData(IWorkspace parentWorkspace, IVersionInfo versionInfo, string replicaName, IGeometry area, IWorkspace childWorkspace, string definitionQuery, string featureDataset)
{
if (childWorkspace == null)
throw new ArgumentNullException("Child workspace is null.");
if (parentWorkspace == null)
throw new ArgumentNullException("Parent workspace is null.");
if (versionInfo == null)
throw new ArgumentNullException("Version name is null.");
if (string.IsNullOrEmpty(replicaName))
throw new ArgumentNullException("Replica name is null.");
if (area == null)
throw new ArgumentNullException("Area geometry is null.");
IVersion oVersion = (parentWorkspace as IVersionedWorkspace).FindVersion(versionInfo.VersionName);
IWorkspace sdeVersionWorkspace = oVersion as IWorkspace;
IGeoDataServer parentGds = InitGeoDataServer(sdeVersionWorkspace),
childGds = InitGeoDataServer(childWorkspace);
CreateFeatureDatasetReplica(parentGds, childGds, versionInfo, replicaName, parentWorkspace, childWorkspace, area, definitionQuery, featureDataset);
Marshal.ReleaseComObject(parentGds);
Marshal.ReleaseComObject(childGds);
}
//Function to create the replica, based on this link http://help.arcgis.com/en/sdk/10.0/arcobjects_net/conceptualhelp/index.html#//0001000003r5000000
private void CreateFeatureDatasetReplica(IGeoDataServer parentGDS, IGeoDataServer childGDS, IVersionInfo versionInfo, string replicaName, IWorkspace parentWorkspace, IWorkspace childWorkspace, IGeometry geometry, string definitionQuery, string featureDatasetName)
{
IList<string> existingReplicas = ReadExistingReplicas(parentGDS);
if (existingReplicas.Contains(replicaName.ToUpper()))
{
throw new Exception("A replica with the following name has already been created: " + replicaName);
}
IEnumDataset datasets = null;
if (!string.IsNullOrEmpty(featureDatasetName))
{
IEnumDataset featureDatasets = parentWorkspace.get_Datasets(esriDatasetType.esriDTFeatureDataset);
IFeatureDataset featureDataset;
while ((featureDataset = featureDatasets.Next() as IFeatureDataset) != null)
{
if (featureDataset.Name == featureDatasetName)
{
datasets = featureDataset.Subsets;
break;
}
}
if (datasets == null)
throw new Exception("Didn't find FeatureDataset " + featureDatasetName + " in the db");
}
else
{
datasets = parentWorkspace.get_Datasets(esriDatasetType.esriDTFeatureClass);
}
IGPReplicaDatasets gpReplicaDatasets = new GPReplicaDatasetsClass();
IDataset dataset;
while ((dataset = datasets.Next()) != null)
{
//temporary workaround to not include a view that is on the feature classes :^)
if (dataset.Name.Contains("VW_") || dataset.Name.Contains("_EVW"))
continue;
if (m_ListExcludedTables.Contains(dataset.Name.Substring(dataset.Name.LastIndexOf(".") + 1).ToUpper()))
continue;
if (!(childWorkspace as IWorkspace2).NameExists[dataset.Type, dataset.Name.Substring(dataset.Name.LastIndexOf(".") + 1)])
continue;
IGPReplicaDataset gpReplicaDataset = new GPReplicaDatasetClass();
gpReplicaDataset.DatasetType = dataset.Type;
gpReplicaDataset.Name = dataset.Name.ToUpper();
gpReplicaDataset.IsPrivate = false;
gpReplicaDataset.UseGeometry = true;
gpReplicaDataset.RowsType = esriRowsType.esriRowsTypeFilter;
if ((dataset as ITable).Fields.FindField("PLTS_COMP_SCALE") != -1)
gpReplicaDataset.DefQuery = definitionQuery; //DefQuery here
else
gpReplicaDataset.DefQuery = "";
gpReplicaDatasets.Add(gpReplicaDataset);
}
IGPReplicaDescription gpReplicaDesc = new GPReplicaDescriptionClass();
gpReplicaDesc.QueryGeometry = geometry;
gpReplicaDesc.SpatialRelation = esriSpatialRelEnum.esriSpatialRelIntersects;
gpReplicaDesc.ModelType = esriReplicaModelType.esriModelTypeSimple;
gpReplicaDesc.SingleGeneration = true;
gpReplicaDesc.ReplicaDatasets = gpReplicaDatasets;
IGPReplicaOptions2 replicaOptions = new GPReplicaOptionsClass();
replicaOptions.AccessType = esriReplicaAccessType.esriReplicaAccessNone;
replicaOptions.RegisterReplicaOnly = true;
ExtractData(datasets, childWorkspace, geometry, definitionQuery);
IReplicationAgent replicationAgent = new ReplicationAgentClass();
replicationAgent.CreateReplica(versionInfo.VersionName, parentGDS, childGDS, replicaName, gpReplicaDesc, replicaOptions);
}
}
For fixing the UI freeze i made the following changes to the button1_Click_1() method:
public partial class FrmReplicaAdmin : Form
{
private void button1_Click_1(object sender, EventArgs e)
{
DataConnectionConfig selectedDatabase = cmboxDatabase.SelectedItem as DataConnectionConfig;
if (selectedDatabase.PlWorkspace == null)
{
statusLabel.Text = "Could not open GeoDatabase (PL)";
return;
}
if (selectedDatabase.DataWorkspace == null)
{
statusLabel.Text = "Could not open GeoDatabase (NIS)";
return;
}
int scaleBand = int.Parse(cmboxScale.SelectedItem.ToString());
string gridName = cmboxGridNr.SelectedItem as string;
IGeometry shapeOfSelectedAOI = getSelectedPolygon(gridName, scaleBand, selectedDatabase);
// adding inputs to list i can pass onto the backgroundWorker
List<object> arguments = new List<object>();
arguments.Add(selectedDatabase.PlWorkspace);
arguments.Add(selectedDatabase.DataWorkspace);
arguments.Add(selectedDatabase.TemplateGdb);
arguments.Add(gridName);
arguments.Add(scaleBand);
arguments.Add(shapeOfSelectedAOI);
arguments.Add(selectedDatabase.DatasetName);
backgroundWorker1.RunWorkerAsync(arguments);
// starting progress bar
progressBarReplica.Visible = true;
lblReplica.Text = "Checking out replica...";
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
List<object> genericlist = e.Argument as List<object>;
IWorkspace ws = (IWorkspace)genericlist[0];
IWorkspace pWs = (IWorkspace)genericlist[1];
string pathToDbTemplate = genericlist[2].ToString();
string gName = genericlist[3].ToString();
int sBand = (int)genericlist[4];
IGeometry shape = (IGeometry)genericlist[5];
string dsName = genericlist[6].ToString();
(ArcMap.Application as IMxApplication2).PauseDrawing = true;
replica.CheckOutReplica(ws, pWs, pathToDbTemplate, gName, sBand, shape, dsName);
(ArcMap.Application as IMxApplication2).PauseDrawing = false;
}
}
This is causing a: "RPC_E_SERVERFAULT(0X80010105)", but the UI isn't freezing anymore. My guess is that it's because i'm initiating the database in the first thread, and then using it in the second. I also sort of get that i can't use a backgroundWorker due to the entire STA and COM-object things with ArcGis, but i'm still not getting all this 100%.
Any help of a possible solution to making my UI responsive, or at least showing some sort of progressbar while the task is running would be nice. The entire process can take a few minutes at times, and the program feels like it's crashed meanwhile due to the freeze.
Edit: I'm referring to ArcMap, forgot to mention that.
How do I discover a paired Bluetooth device that's currently disconnected?
I've attempted the following code using the Windows 10 SDK:
using Windows.Devices.Enumeration;
using Windows.Devices.Bluetooth.Rfcomm;
var serviceInfoCollection = await DeviceInformation.FindAllAsync(RfcommDeviceService.GetDeviceSelector(RfcommServiceId.SerialPort));
I've also tried the following:
using System;
using System.Diagnostics;
using System.Management;
public class Win32_UsbDriveWatcher
{
ManagementEventWatcher m_watcher;
public delegate void DeviceInsertedEventHandler(object sender, Win32_UsbDriveInsertEventArgs e);
public event DeviceInsertedEventHandler DeviceInserted;
public event EventHandler DeviceRemoved;
public void Start(int pollingInterval)
{
try
{
var queryString =
"SELECT * " +
" FROM __InstanceOperationEvent" +
" WITHIN " + pollingInterval +
" WHERE TargetInstance ISA 'Win32_PnPEntity'";
var processQuery = new EventQuery(queryString);
m_watcher = new ManagementEventWatcher(processQuery);
m_watcher.EventArrived += EventArrived;
m_watcher.Start();
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
void EventArrived(object sender, EventArrivedEventArgs e)
{
var instance = ((PropertyData)(e.NewEvent.Properties["TargetInstance"]));
var obj = (ManagementBaseObject)instance.Value;
var args = new Win32_UsbDriveInsertEventArgs();
if ((string)obj["InterfaceType"] == "BLUETOOTH")
{
args.IsCreated = (obj.ClassPath.ClassName == "__InstanceCreationEvent");
args.DriveName = GetDriveLetterFromDisk((string)obj["Name"]);
if (args.IsCreated)
{
DeviceInserted?.Invoke(this, args);
}
else
{
DeviceRemoved?.Invoke(this, EventArgs.Empty);
}
}
}
static string GetDriveLetterFromDisk(string name)
{
name = name.Replace("\\", "\\\\");
var query = "ASSOCIATORS OF {Win32_DiskDrive.DeviceID='" + name + "'} WHERE AssocClass = Win32_DiskDriveToDiskPartition";
var queryDrive = new ObjectQuery(query);
using (var searcherDrive = new ManagementObjectSearcher(queryDrive))
{
foreach (ManagementObject drive in searcherDrive.Get())
{
query = "ASSOCIATORS OF {Win32_DiskPartition.DeviceID='" +
drive["DeviceID"] +
"'} WHERE AssocClass = Win32_LogicalDiskToPartition";
var queryPartition = new ObjectQuery(query);
using (var searcherPartition = new ManagementObjectSearcher(queryPartition))
{
foreach (ManagementObject disk in searcherPartition.Get())
{
return (string)disk["Name"];
}
}
}
return string.Empty;
}
}
}
public class Win32_UsbDriveInsertEventArgs : EventArgs
{
public bool IsCreated;
public string DriveName;
}
Regardless of the code snippets that I've attempted, I'm still unable to discover paired disconnected devices.
Any suggestions?
There are few way:
Use WM_DEVICE_CHANGE message to know when device connected and disconnected.
Once you found all paired devices query each for its services. Not available (disconnected) device reports error.
Try to connect to device's SDP service using DeviceIOControl (the best way).
I'm doing an enhancement work on a project. This is Original code that parse paramenter string to Summary.aspx on data creation. but then realise when the user created the data there is no notification of "Successfully Submitted" therefore i need to create a semi-static SuccessPage.aspx to show use that they have successfully submitted form. and click the URL to redirect to Summary.aspx
String Parameters = "type=1&data1=" + _rguid.ToString() + "&data2=" + _handsetplanvalue.Text.ToString();
Response.Redirect("Summary.aspx?" + Parameters.ToString());
New code
Response.Redirect("SuccessPage.aspx?" + Parameters.ToString());
The image shows how the semi static page will look like. In the successpage it will check if the type=1 from parameter and if it is 1 the url willResponse.Redirect("Summary.aspx?" + Parameters.ToString());
if type=2 Response.Redirect("Summary2.aspx?" + Parameters.ToString());
My SuccessPage is clean i have no idea how to code it please help
public partial class STSS_stsSuccessPage : BasePage
{
protected static readonly System.Web.UI.Page page = null;
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
Master.strHeader = HttpContext.GetGlobalResourceObject("BaseLocale", "lbl_stsSuccessPage_Desc") as string;
?????
}
}
}
var type = Request.QueryString["type"];
if (type == "1")
{
var data= Request.QueryString["data1"];
var data2= Request.QueryString["data2"];
String Parameters = data1+ data2;
}
if (type == "2")
{
var data1= Request.QueryString["data1"];
var data2= Request.QueryString["data2"];
var data3= Request.QueryString["data3"];
var data4= Request.QueryString["data4"];
String Parameters = data1+ data2+ data3+ dat4;
}
The snippet below isn't summing the variables (int)winTemp and playerWIn. I've verified that both variables are assigned the correct value by printing to screen before calling createXML(). My theory is that you cannot evaluate equations while creating new XELEMENT's. Can anyone verify this?
new XElement("playerWin", (int)winTemp + playerWin),
If I do it outside of XElement, like the commented lines in saveXML(), it works as intended.
If the file did not exist - Excepted XML output should be Wins=10, Loss=1, Tie=0.
If the file was existed - Excepted XML output should be Wins=20, Loss=2, Tie=0.
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using System.Text;
using System.IO;
using System.Threading.Tasks;
namespace Testing_LINQ_to_XML
{
class Program
{
static void Main()
{
Player p = new Player();
p.readXML();
p.toScreen();
p.saveXML();
p.readXML();
p.toScreen();
p.Exit();
}
}
public class Player
{
public string path;
public string playerName;
public int playerWin = 10;
public int playerLoss = 1;
public int playerTie = 0;
public int winTemp;
public int lossTemp;
public int tieTemp;
public Player()
{
Console.WriteLine("Enter player Name...");
playerName = Console.ReadLine();
Console.WriteLine("n: " + playerName);
getPath();
Console.WriteLine("p: " + path);
Console.ReadLine();
}
public string getPath()
{
path = (#"..\XML Saves\" + playerName + ".xml");
return path;
}
public void toScreen()
{
Console.WriteLine("\nYour Record Is:\n");
Console.WriteLine("Wins: " + playerWin);
Console.WriteLine("Losses: " + playerLoss);
Console.WriteLine("Ties: " + playerTie);
}
public void saveXML()
{
if (File.Exists(path))
{
readXML();
File.Delete(path);
//playerWin = (int)winTemp;
//playerLoss = (int)lossTemp;
//playerTie = (int)tieTemp;
createFile();
}
else
{
createFile();
}
}
public void createFile()
{
XDeclaration _obj = new XDeclaration("1.0", "utf-8", "");
XNamespace gameSaves = "gameSaves";
XElement fileNew = new XElement("Root",
new XElement("Player",
new XElement("playerName", playerName),
new XElement("Stats",
new XElement("playerWin", (int)winTemp + playerWin),
new XElement("playerLoss", (int)lossTemp + playerLoss),
new XElement("playerTie", (int)tieTemp + playerTie))));
fileNew.Save(path);
Console.WriteLine("Save created: " + path);
}
public void readXML()
{
if (File.Exists(path))
{
var winTemp = new XElement("playerWin", playerWin);
var lossTemp = new XElement("playerLoss", playerLoss);
var tieTemp = new XElement("playerTie", playerTie);
}
else
{
Console.WriteLine("\nYou don't have any stats to show yet. Get playing!!!");
}
}
public void Exit()
{
Console.WriteLine("Press any key to exit.");
Console.ReadLine();
}
}
}
XML output:
<Root>
<Player>
<playerName>Name</playerName>
<Stats>
<playerWin>10</playerWin>
<playerLoss>1</playerLoss>
<playerTie>0</playerTie>
</Stats>
</Player>
</Root>
The locally scoped winTemp variable is hiding the instance variable (inside readXML() method). Thus winTemp instance variable does not get set at all and holds the default value, i.e. 0, by the time of addition.
I am using reflection and WSDL to call web services on the fly through dynamically constructed proxy classes, and I have just added some overloaded web methods to one of the web services I am calling. Now I get an 'Ambigious match' error when trying to Invoke (via reflection) the method.
Here is the class that builds the service proxy and has a method to invoke any given web method in that proxy by name:
public class ServiceProxy
{
public ServiceMetadata Metadata { get; private set; }
public RemoteServiceElement Element { get; private set; }
public string IpAddress { get; private set; }
private object serviceProxy;
private string serviceAsmx;
public ServiceProxy(RemoteServiceElement element)
{
IpAddress = element.IpAddress;
Element = element;
serviceAsmx = "http://" + element.IpAddress + ":" + element.Port + "xxxx.asmx"
Build(serviceAsmx, "xxxx");
}
public ServiceProxy(string ip, string _asmx, string _serviceName)
{
IpAddress = ip;
serviceAsmx = _asmx;
Build(_asmx, _serviceName);
}
private void Build(string webServiceAsmx, string serviceName)
{
WebClient client = new WebClient();
Metadata = ServiceMetadata.OpenWsdl(webServiceAsmx);
Stream stream = client.OpenRead(webServiceAsmx + "?wsdl");
ServiceDescription description = ServiceDescription.Read(stream);
ServiceDescriptionImporter importer = new ServiceDescriptionImporter();
importer.ProtocolName = "Soap12";
importer.AddServiceDescription(description, null, null);
importer.Style = ServiceDescriptionImportStyle.Client;
importer.CodeGenerationOptions = CodeGenerationOptions.GenerateProperties;
CodeNamespace nmspace = new CodeNamespace();
CodeCompileUnit unit1 = new CodeCompileUnit();
unit1.Namespaces.Add(nmspace);
ServiceDescriptionImportWarnings warning = importer.Import(nmspace, unit1);
if (warning == 0)
{
CodeDomProvider provider1 = CodeDomProvider.CreateProvider("CSharp");
string[] assemblyReferences = new string[5] { "System.dll", "System.Web.Services.dll", "System.Web.dll",
"System.Xml.dll","System.Data.dll" };
CompilerParameters param = new CompilerParameters(assemblyReferences);
CompilerResults results = provider1.CompileAssemblyFromDom(param, unit1);
if (results.Errors.Count > 0)
{
foreach (CompilerError err in results.Errors)
{
Logger.Write("Compiler error assembling " + webServiceAsmx + " - " + err.ErrorText);
}
throw new Exception("Compiler error occurred calling the web service. Check log for details.");
}
serviceProxy = results.CompiledAssembly.CreateInstance(serviceName);
Logger.Write("Proxy service at + " + serviceAsmx + " assembled successfully");
}
}
public object Invoke(string methodName, object[] args = null)
{
MethodInfo info = serviceProxy.GetType().GetMethod(methodName);
object asmxResults = default(object);
try
{
asmxResults = info.Invoke(serviceProxy, args);
Logger.Write("Remote proxy at " + serviceAsmx + " - " + methodName + " - " + "invoked successfully");
}
catch (Exception e)
{
Logger.Write("Error invoking proxy class at " + serviceAsmx + " - " + e.InnerException);
}
return asmxResults;
}
}
This worked fine before I added any overloads. So I am guessing that using reflection + overloads may be causing an issue.
Here is a mock-up example of one of the WebMethods that causes the problem:
[WebMethod (MessageName="GetFoos")]
public List<Foo> GetFoos(DateTime dt)
{
// performs linq query
}
[WebMethod (MessageName = "GetFoosDynamic")]
public List<Foo> GetFoos(Expression exp)
{
// linq query
}
Same method name, different parameters + different 'MessageName' which is supposed to work for web services.
Thanks for any help.
SOAP doesn't support method overloading, but it looks like you've overridden your method name with the WebMethod attribute, so you should be calling the names you've defined within that attribute when you make your SOAP call.