This question already has an answer here:
Interaction between forms — How to change a control of a form from another form?
(1 answer)
Closed 5 years ago.
I know the Title Issue is not unique and lot of Messages available. Reason why I am opening a thread is that I'm really struggling to understand the issue based on my project.
Recently I tried to start a WinForm to get values from an REST API.
Just as a beginning test on the Form1 once clicking the metroButton1 I should get a SessionToken to the metroTextBox1.Text, which works.
Where I'm struggling is to use that Output as an Input for the getvirtualmachine Class.
Once using the Form1.connect() in the class to get the SessionToken, i'am getting following Error:
An object reference is required for the non-static field, method, or property 'Form1.connect()'
Not sure how I could make that globally to use it as Input for several classes. Guessing I'm making somehow/somewhere a big mistake.
FORM1
public partial class Form1 : MetroFramework.Forms.MetroForm
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{ }
public string connect()
{
var httpWebRequest = (HttpWebRequest)WebRequest.Create("http://localhost:35113/api/sessions/start");
httpWebRequest.Headers["Authorization"] = "Basic " + Convert.ToBase64String(Encoding.Default.GetBytes(metroTextBox3.Text + ":" + metroTextBox4.Text));
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "POST";
using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
string json = JsonConvert.SerializeObject(new
{
ServerPort = "35107",
Username = metroTextBox3.Text,
Password = metroTextBox4.Text,
Domain = metroTextBox5.Text
});
streamWriter.Write(json);
}
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
dynamic item = Newtonsoft.Json.JsonConvert.DeserializeObject(result);
return (string)item.Data;
}
}
public void metroButton1_Click(object sender, EventArgs e)
{
metroTextBox1.Text = connect();
}
GetVirtualMachines Class
public class GetVirtualMachines
{
public string gVM()
{
var httpWebRequest = (HttpWebRequest)WebRequest.Create("http://localhost:35113/api/vms/list/");
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "GET";
using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
string json = JsonConvert.SerializeObject(new
{
SessionToken = Form1.connect(),
});
streamWriter.Write(json);
}
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
dynamic item = Newtonsoft.Json.JsonConvert.DeserializeObject(result);
return item;
}
}
}
You either need to make the method static, so it's part of the class definition rather than an instance method, i.e.
public static string connect()
or create an instance of Form1 and use that to call connect(). However, that ends up creating another problem because now you've got a form hanging out in memory that no one ever sees (and will prevent the application from closing), so you really should ensure it gets disposed, i.e.
using(var form = new Form1)
{
form.connect();
}
However, my bigger question would be, why are you using a Form to perform this operation at all. It seems to me more like the connect() method belongs on the GetVirtualMachines class.
At the moment, given the code you've shown, this is really bad use of the toolset.
You need to rethink your approach here. The Windows Form (Form1) is the actual GUI that the user sees. Your backend GetVMs class appears to be something purely for data processing that the user doesn't really interact with.
So you can't really have the GetVMs class create a new instance of your Windows Form because, well, there is no way for the user to see the form that you new up (simplifying a lot here!).
I would solve this by following a relatively standard view/controller type pattern:
Your windows form is the view -- that is what the user sees
The form has an instance of your GetVMs class private GetVirtualMachines VMGetter
The form calls methods of GetVirtualMachines via its instance of the class (VMGetter), passing an argument with whatever is in the text box.
This is still not the greatest idea in the simplified approach I gave because you'll hang the UI thread. But, hopefully it gives you a jumping off point.
Edit: I'd also move the connect method and its business logic to your GetVMs class. Typically we try to avoid business logic in all view/display classes.
Related
I am using Abot in a way that I have a WPF application which displays a browser control (CefSharp).
The user logs in and whichever possible custom authentication the site is using will work while crawling in the same way as if the user were actually browsing the site.
Thus, when I crawl, I want to use this browser control to make the request and simply return the page data.
Therefore I've implemented my custom PageRequester, complete listing below.
The problem is that with CefSharp, as with other browser controls, it's not possible to get the HttpWebRequest/Response associated with a CrawlPage.
Without setting these two properties, Abot does not proceed the crawl further.
Is there something I can do to circumvent this problem?
Code listing:
using Abot.Core;
using Abot.Poco;
using CefSharp.Wpf;
using System;
using System.Net;
using System.Text;
using System.Threading;
public class CefPageRequester : IPageRequester
{
private MainWindowDataContext DataContext;
private ChromiumWebBrowser ChromiumWebBrowser;
private CrawlConfiguration CrawlConfig;
private volatile bool _navigationCompleted;
private string _pageSource;
public CefPageRequester(MainWindowDataContext dataContext, ChromiumWebBrowser chromiumWebBrowser, CrawlConfiguration crawlConfig)
{
this.DataContext = dataContext;
this.ChromiumWebBrowser = chromiumWebBrowser;
this.CrawlConfig = crawlConfig;
this.ChromiumWebBrowser.FrameLoadEnd += ChromiumWebBrowser_FrameLoadEnd;
}
public CrawledPage MakeRequest(Uri uri)
{
return this.MakeRequest(uri, cp => new CrawlDecision() { Allow = true });
}
public CrawledPage MakeRequest(Uri uri, Func<CrawledPage, CrawlDecision> shouldDownloadContent)
{
if (uri == null)
throw new ArgumentNullException("uri");
CrawledPage crawledPage = new CrawledPage(uri);
try
{
//the browser control is bound to the address of the data context,
//if we set the address directly it breaks for some reason, although it's a two way binding.
this.DataContext.Address = uri.AbsolutePath;
crawledPage.RequestStarted = DateTime.Now;
crawledPage.DownloadContentStarted = crawledPage.RequestStarted;
while (!_navigationCompleted)
Thread.CurrentThread.Join(10);
}
catch (WebException e)
{
crawledPage.WebException = e;
}
catch
{
//bad luck, we should log this.
}
finally
{
//TODO must add these properties!!
//crawledPage.HttpWebRequest = request;
//crawledPage.HttpWebResponse = response;
crawledPage.RequestCompleted = DateTime.Now;
crawledPage.DownloadContentCompleted = crawledPage.RequestCompleted;
if (!String.IsNullOrWhiteSpace(_pageSource))
crawledPage.Content = this.GetContent("UTF-8", _pageSource);
_navigationCompleted = false;
_pageSource = null;
}
return crawledPage;
}
private void ChromiumWebBrowser_FrameLoadEnd(object sender, CefSharp.FrameLoadEndEventArgs e)
{
if (!e.IsMainFrame)
return;
this.ChromiumWebBrowser.Dispatcher.BeginInvoke(
(Action)(() =>
{
_pageSource = this.ChromiumWebBrowser.GetSourceAsync().Result;
_navigationCompleted = true;
}));
}
private PageContent GetContent(string charset, string html)
{
PageContent pageContent = new PageContent();
pageContent.Charset = charset;
pageContent.Encoding = this.GetEncoding(charset);
pageContent.Text = html;
pageContent.Bytes = pageContent.Encoding.GetBytes(html);
return pageContent;
}
private Encoding GetEncoding(string charset)
{
Encoding e = Encoding.UTF8;
if (charset != null)
{
try
{
e = Encoding.GetEncoding(charset);
}
catch { }
}
return e;
}
}
The question can also be phrased as: how to avoid having to create a HttpWebResponse from a stream? Which seems impossible, given MSDN says:
You should never directly create an instance of the HttpWebResponse
class. Instead, use the instance returned by a call to
HttpWebRequest.GetResponse.
I would have to actually post the request to get the response, which is precisely what I want to avoid by having a web browser control.
As you are aware, lots of functionality depends on the HttpWebRequest and HttpWebResponse being set. I've ordered a few options for you off the top of my head...
1) Refactor Abot to use some POCO Abstraction instead of those classes. Then just have an converter that converts the real HttpWebRequest and HttpWebResponse to those POCO types as well as a converter that converts your browser objects response into those POCOs.
2) Create a CustomHttpWebRequest and CustomHttpWebResponse that inherit from the .net classes so you can access/override the public/protected properties which may allow you to manually create an instance that models the request/response that your browser component returns to you. I know this can be tricky but may work (I've never done it so I can't say for sure).
3) [I HATE THIS IDEA. It SHOULD BE YOUR LAST RESORT] Create a real instance of these classes and use reflection to set whatever properties/values need to be set to satisfy all of Abot's usages.
4) [I HATE THIS IDEA EVEN WORSE] Use MS Fakes to create shims/stubs/fakes to the properties and methods of the HttpWebRequest and HttpWebResponse. Then you could configure it to return your values. This tool is usually only used for testing but I believe it can be used for production code if you are desperate, don't care about performance and/or are insane.
I also included the terrible ideas as well to just in case they help you spark some thought. Hope that helps...
We're creating a WPF app in which we execute python scripts from different Test Stations and show the output in its corresponding output panel, To run the scripts in parallel we are using Task but when we run the scripts in parallel from the stations, We are getting the output of other stations also into the station that is started first, we're using the following code,
private void ZmqStatusListener(string endPoint)
{
using (Context context = new Context())
{
StatusPort = string.Empty;
TestResultPort = string.Empty;
using (Socket server = context.Socket(SocketType.REP))
{
try
{
if (isStatusContextActive == false || isPortChanged == true)
{
server.Bind(endPoint);
isStatusContextActive = true;
}
}
catch (ZMQ.Exception ex)
{
if (ex.Errno != 100)
{
string IPCPort = _globalParameters.GlbParam.GlbParamIpcStartPort;
if (IPCPort == string.Empty)
{
IPCPort = "0";
}
if (endPoint == EditorConstants.PortAddress.PortPrefix + IPCPort)
{
StatusPort = endPoint;
TestReultError = EditorConstants.CommonMessageTypes.TestReultError + ex.Message + EditorConstants.CommonMessageTypes.StackTraceMessage + ex.StackTrace;
}
StopExecOfScript(default(object));
isCancelledtask = true;
ScriptStatusDesc = new ScriptStatusDesc()
{
Status = "Failed",
statusDescription = "Failed"
};
}
}
while (true)
{
string message = server.Recv(Encoding.UTF8);
UpdateTestResults(message);
server.Send(" ACK", Encoding.UTF8);
// if (message == "Test Passed")
//break;
}
}
}
}
and for testing purpose we're breaking the while loop in this code based on a test message we kept in the python script, then we are able to get the output in the respective station correctly but this way we can only run in a synchronous fashion which we don't want as we require to run the test stations in parallel and the while loop should not break as it should be listening for the response.
We were able to solve the issue by getting clues doing a sample app to reproduce the issue and to first know whether our ClrZmq pattern was correct for us or not and it is correct. The resolution we followed is that when we needed to bind that data to its corresponding View's Model object in its ViewModel so had to retrieve View's DataContext which is of Type ISomeXViewModel for the particular TestStation using an Id of that TestStation we did this cos all of our TestStations are dynamically added and we even store it to be accessed wherever necessary. This issue was caused to due multiple instances of UserControls so we explicitly needed to update the TestStation manually with a little more effort.
Sample Code Snippet
private void BindTestResult(string xmlPayLoad)
{
// converting xmlPalLoad to a class/model object
ITestStationViewModel viewModel = (ITestStationViewModel)((IView)DynamicTestStationsGrid.Children[StationNumber].Content).DataContext;
// IView class has DataContext property so I am type casting the Content which is ContentControl to IView type first and later to ITestStationViewModel
viewModel.TestStationModel = xmlPayLoadModel;
}
Thanks.
Im new with WP8.
Im asking which class i should use to get data from a webservice.
I need to launch many Asynchronous requests. 1request=1 image and i need a lot of image in my UI.
in a first time i tried with the webclient class but i can't manage the content type "application/octet-stream" with it so at this time im trying to use the HttpClient class but I need your help. I also need to use Authentication with credantials to connect to the webservice.
In a second time i need to convert the data obtained in Bitmapimage.But i think it's an easier part.I would probably use the Stream class for that.*
thanks for your help
Sry for my english BTW :p
Im not sure it would help but i join a sample of the code,i used a dictionnary of HttpClient because i encountered an error while trying to launch several async requests on the same instance of a Webclient... the 2 lists remain empty...
Dictionary<string, HttpClient> HttpClientDic = new Dictionary<string, HttpClient>();
List<byte[]> imageDataBlocksPresta = new List<byte[]>();
List<byte[]> imageDataBlocksCollab = new List<byte[]>();
public async Task< List<byte[]>> DownloadAsyncRecherchePhoto(string uri,string critere = "")
{
string password = Authentification.MainPage.Password;
string user = Authentification.MainPage.User;
string domain = Authentification.MainPage.Domain;
i++;
var handler = new HttpClientHandler { Credentials = new NetworkCredential(user, password, domain) };
HttpClientDic.Add("Client" + i.ToString(), new HttpClient(handler));
if (critere == "presta")
{
imageDataBlocksPresta.Add(await HttpClientDic["Client" + i.ToString()].GetByteArrayAsync(uri));
return imageDataBlocksPresta;
}
else if (critere == "collab")
{
imageDataBlocksCollab.Add(await HttpClientDic["Client" + i.ToString()].GetByteArrayAsync(uri));
return imageDataBlocksCollab;
}
//gérer l'erreur
else return null;
public void FindCityName()
{
string url = "http://maps.google.com/maps/geo?q=39.920794,32.853902&output=json&oe=utf8&sensor=true&key=MYKEY";
var w = new WebClient();
Observable.FromEvent<DownloadStringCompletedEventArgs>(w, "DownloadStringCompleted").Subscribe(r =>
{
var deserialized = JsonConvert.DeserializeObject<RootObject>(r.EventArgs.Result);
string s = deserialized.Placemark[0].AddressDetails.Country.SubAdministrativeArea.Locality.LocalityName;
/// setCity() and City=s produce the same thing
setCity(s);
City = s;
//foreach (var item in deserialized.Placemark)
//{
// //MessageBox.Show(item.AddressDetails.Country.SubAdministrativeArea.Locality.LocalityName);
// City = (string)item.AddressDetails.Country.SubAdministrativeArea.Locality.LocalityName;
//}
//Problem here >>>>>
////MessageBox.Show(City);
});
w.DownloadStringAsync(new Uri(url));
}
Problem:
I am working on a windows phone 7 application and I need to find the "City Name" from GPS coordinates in order to move forward...
I found the code above on the internet and tried it. I can see the city name by using these codes(Message.Box(City) show exactly what I want, the city name). However, this line of code
deserialized.Placemark[0].AddressDetails.Country.SubAdministrativeArea.Locality.LocalityName;
which gives me the city name seems to give a volatile string value.
For example, I created a method which assigns the value of string variable "s" to the string field of my class, name City. If I try to get the City's content after calling FindCityName() method, I see that City's content is not updated.
Again, same thing happens then I call the code line under the comment "Problem here >>>>>" that MessageBox.Show(City) shows nothing new...
Can someone explain me the reason of my problem?
you put this question on my blog as well, but I will answer it here. I feel a bit responsible for putting up the sample code in the first place ;-)
I am going to assume the class containing your code looks like this:
public class MyClass
{
private void MyMethod()
{
FindCityName();
MessageBox.Show(City);
}
private void FindCityName()
{
// Code omitted - see your question
}
private string City;
}
There is nothing volatile about the string. Your problem is asynchronicity. If you look carefully you will see that I use an observable that fires when the DownloadStringCompleted is fired. The code inside Observable.Event is only called when the download is finished but that happens asynchronously. But what I assume you do is call the FindCityName method and then directly trying to access results like I show in the MyMethod method. That's like directly wanting the result after firing the request. The results are not in yet! It's like a web page downloading - it takes a while. You can fix that with a callback, something like this:
public class MyClass
{
private void MyMethod()
{
FindName();
}
public void FindCityName()
{
string url = "http://maps.google.com/maps/geo?q=39.920794,32.853902&output=json&oe=utf8&sensor=true&key=MYKEY";
var w = new WebClient();
Observable.FromEvent<DownloadStringCompletedEventArgs>(w, "DownloadStringCompleted").Subscribe(r =>
{
var deserialized = JsonConvert.DeserializeObject<RootObject>(r.EventArgs.Result);
City = deserialized.Placemark[0].AddressDetails.Country.SubAdministrativeArea.Locality.LocalityName;
DoneDownloading();
});
w.DownloadStringAsync(new Uri(url));
}
private string City;
private void DoneDownloading
{
MessageBox.Show(City);
}
}
Does that help?
I would recommend you to use this Google Map API
http://maps.googleapis.com/maps/api/geocode/json?latlng=39.920794,32.853902&sensor=true
And once you get JSON response in your request. You can parse easily with NEWTONSOFT for wp7
WebClient wc = new WebClient();
var json = (JObject)JsonConvert.DeserializeObject(wc.DownloadString(url));
var locality= json["results"]
.SelectMany(x => x["address_components"])
.FirstOrDefault(t => t["types"].First().ToString() == "locality");
var name = locality!=null ? locality["long_name"].ToString() : "";
I have created a REST Web Service that in all other ways is working how I want it to work.
I have a main class that contains contacts, in that class, there are 2 other lists of classes that I have created.
My main class, and one of the lists comes through the call with all information intact. However, the second class is comming through as empty. It has each item in the list, but each list item is empty.
Web Service Function
[OperationContract]
[WebGet(UriTemplate = "/Login/{IQPid}/{Password}")]
public IQP_Contacts Login(string IQPid, string password)
{
int iqpID = 0;
try
{
iqpID = int.Parse(IQPid);
}
catch { return null; }
IQP_Contacts contact = this.Repository.Contacts.Find(delegate(IQP_Contacts c) { return c.IqpID == iqpID; });
if (contact.Password == password)
{
return contact;
}
else return null;
}
Code calling the web service
WebClient proxy = new WebClient();
byte[] abc = proxy.DownloadData((new Uri("http://localhost:53468/IQP_Service.svc/Login/" + ID + "/" + password )));
Stream strm = new MemoryStream(abc);
DataContractSerializer obj = new DataContractSerializer(typeof(IQP_Contacts));
IQP_Contacts contact = (IQP_Contacts)obj.ReadObject(strm);
As you can see below, my webservice's class contains the information, but the the webpage does not
If anyone has any ideas, Please let me know. I am lost on this one. Something this simple shouldn't be this broken. Thanks
Check out the documentation about DataContractSerializer to see what does and does not get serialized by default:
http://msdn.microsoft.com/en-us/library/cc656732.aspx
It is hard to tell without seeing your classes. But it is possible that your Files property is readonly (only has a get accesser with no set) then it would not get serialized.
It could also depend on if you have selectively applied [DataContract]/[DataMember] attributes on your classes. This affects the behavior of what DataContractSerializer will serialize/deserialize. You would need to indicate that your "Files" property on IQP_RestWebService.Entitys.IQP_Contacts class is marked with a [DataMember] attribute and that you have a [DataContract] on the IQP_RestWebService.Entitys.Files class.