Προς το περιεχόμενο

Προτεινόμενες αναρτήσεις

Δημοσ.

Καλημέρα, έχω δημιουργήσει έναν wcf server που τον ενεργοποιώ και τον απενεργοποιώ από μια windows form. Τώρα σε αυτόν τον server έχω βάλει ένα service όπου όταν πατάω στον browser το link: http://myhost:myport/changeLabel?text=mytextθέλω να αλλάζει το Text από ένα label της Windows Form όπου ενεργοποιείτε ο server. Εδώ είναι οι κώδικες:

 

Tameio.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.ServiceModel;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;
using System.Data.SqlClient;

namespace Tameio
{
    
    public partial class Ταμείο : Form
    {
        ServiceHost host;
       
        string WCFPort="8001";

        public Ταμείο()
        {
            InitializeComponent();
        }

        private void StartWCFServer()
        {
                if (host == null)
                {
                    Uri baseAddress = new Uri("http://localhost:"+WCFPort+"/");
                    host = new ServiceHost(typeof(WCFService), baseAddress);
                    host.AddServiceEndpoint(typeof(IWCFService), new WSHttpBinding(), "Services");
                  //  try
                   // {
                        host.Open();
                        label1.Text = "Ο server είναι ενεργός";
                  //  }
                   // catch
                  //  {
                  //      MessageBox.Show("Βεβαιωθείτε ότι έχετε δικαιώματα διαχειριστή σε αυτόν τον υπολογιστή");
                  //  }
                }
                else
                {
                    MessageBox.Show("Υπήρξε πρόβλημα κατά του άνοιγμα του WCF Server. Είτε ο WCF Server είναι Ενεργός, είτε το Port: "+WCFPort+" χρεισιμοποιείτε κάπου αλλού, είτε η IP του δικτύου δεν είναι σωστή");
                }
        }

        private void btn_StopServer_Click(object sender, EventArgs e)
        {
            if (host != null)
            {
                host.Close();
            }
            else MessageBox.Show("Ο Server είναι ήδη Απενεργοποιημένος");
        }

        private void button1_Click_1(object sender, EventArgs e)
        {
            StartWCFServer();
        }
    }
}

IWCFService.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.ServiceModel.Web;
using System.IO;

namespace Tameio
{

    [ServiceContract]
    public interface IWCFService
    {
        [OperationContract]
        [WebInvoke(Method = "GET",
            ResponseFormat = WebMessageFormat.Json,
            BodyStyle = WebMessageBodyStyle.Bare,
            UriTemplate = "changeLabel?text={txt}")]
        string changeLabel(string txt);  
    }
}

WCFService.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.ServiceModel.Web;
using System.Drawing;
using System.IO;
using System.Runtime.Serialization.Json;
using System.Windows.Forms;
namespace Tameio
{
    public class WCFService : Ταμείο, IWCFService
    {


        public string changeLabel(string text)
        {
                label1.Text = text;
                return "JOB DONE. Label1.Text = "+text;
        }
    }
}

App.config

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.serviceModel>
    <services>
      <service behaviorConfiguration="ServiceBehaviour" name="Tameio.WCFService">
        <endpoint address="" behaviorConfiguration="web" binding="webHttpBinding"
          bindingConfiguration="webHttpBindingDev" contract="Tameio.IWCFService" />
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>

        <behavior name="ServiceBehaviour">
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="false" />
          <serviceDebug httpsHelpPageEnabled="true"  httpHelpPageEnabled="true" includeExceptionDetailInFaults="true" />
        </behavior>
      </serviceBehaviors>
      <endpointBehaviors>
        <behavior name="web">
          <webHttp />
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <protocolMapping>
      <add binding="basicHttpsBinding" scheme="https"  />
    </protocolMapping>
    
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"/>
    <bindings>
      <webHttpBinding>
        <binding name="webHttpBindingDev">
          <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647"  maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
          <security mode="None" />
          
        </binding>
      </webHttpBinding>
      
    </bindings>
    
  </system.serviceModel>
  <system.webServer>
    
    <modules runAllManagedModulesForAllRequests="true"/>
    <directoryBrowse enabled="true" />
  </system.webServer>
</configuration>

Τώρα το return της function changeLabel το εμφανίζει κανονικά στον browser σε μορφή json αλλά το label.Text δεν αλλάζει. Ίσως θελει delegate; event; callback; δεν ξέρω.

Δημοσ. (επεξεργασμένο)

Μπορείς απλα είτε να βάλεις το form σαν static property στο tameio.cs.

Η αλλιώς θα κάνεις public μια property with change notification όπως εδώ

 

http://msdn.microsoft.com/en-us/library/ms743695%28v=vs.110%29.aspx

Και να την τροποποίησεις ώστε να δέχεται παράμετρο και όταν καλείται να τροποποιεί το label.

Επεξ/σία από Papakaliati
Δημοσ.

Δεν μπορώ να χρησιμοποιήσω το παράδειγμα που μου έδειξες διότι χρησιμοποιώ ήδη ένα interface στην WCFSerivce.cs.


Το πρόβλημα λύθηκε. Απλά πρόσθεσα Thread στη Form (tameio.cs) 

public void TextThread(string txt)
        {
            Thread clientThread = new Thread(new ParameterizedThreadStart(ThreadToChangeText));
            clientThread.IsBackground = true;
            clientThread.Start(txt);
        }


        private void ThreadToChangeText(object txt)
        {
            MessageBox.Show(txt.ToString());
            Thread.CurrentThread.Abort();
        }

Και το κάλεσα από τη κλάση WCFService.cs

 

public string changeLabel(string text)
{
TextThread(text);
return "JOB DONE. Label1.Text = "+text;
}
Δημοσ.

Παντως δεν είναι safe να αλλάζεις properties των Controls από διαφορετικό thead.

Αντί για

label.Text="this is text";  

πρεπει να γραψεις

label.BeginInvoke(((Action)(() => label.Text = "this is text")));

Ουτε Abort χρειάζεται οταν τελειώσει το thread.

Δημοσ.

Παντως δεν είναι safe να αλλάζεις properties των Controls από διαφορετικό thead.

Αντί για

label.Text="this is text";  

πρεπει να γραψεις

label.BeginInvoke(((Action)(() => label.Text = "this is text")));

Ουτε Abort χρειάζεται οταν τελειώσει το thread.

 

Φίλε το έκανα έτσι γιατί το label δεν αλλάζει αλλιώς αλλά παρ όλα αυτά παίρνω αυτό το exception:

Invoke or BeginInvoke cannot be called on a control until the window handle has been created.
Δημοσ.

Δοκιμασε το παρακατω, δεν το εχω δοκιμασει με services αλλα 99% το περιπτωσεων που περνω το ιδιο λαθος με σενα δουλευει.

public void TextThread(string txt)
{
    Action action = () => { label1.Text = txt; };
    if (InvokeRequired)
    {
        BeginInvoke(new MethodInvoker(action));
    }
    else
    {
        action();
    }
}
Δημοσ.

 

Δοκιμασε το παρακατω, δεν το εχω δοκιμασει με services αλλα 99% το περιπτωσεων που περνω το ιδιο λαθος με σενα δουλευει.

public void TextThread(string txt)
{
    Action action = () => { label1.Text = txt; };
    if (InvokeRequired)
    {
        BeginInvoke(new MethodInvoker(action));
    }
    else
    {
        action();
    }
}

 

Δεν πετάει exception αλλά δεν αλλάζει το label.text. Κάτι παίζει δεν μπορώ να καταλάβω τι. Αν βάλω μέσα στο thread label1.Text=txt; χωρίς invoke δεν με πετάει exception και δεν αλλάζει κιόλας. Μα δεν έπρεπε να πετάει exception ότι θέλει να γίνει invoke; Εδώ τώρα είναι σαν να μην υπάρχει thread.

Δημοσ.

Δεν πετάει exception αλλά δεν αλλάζει το label.text. Κάτι παίζει δεν μπορώ να καταλάβω τι. Αν βάλω μέσα στο thread label1.Text=txt; χωρίς invoke δεν με πετάει exception και δεν αλλάζει κιόλας. Μα δεν έπρεπε να πετάει exception ότι θέλει να γίνει invoke; Εδώ τώρα είναι σαν να μην υπάρχει thread.

Δοκιμασε με

try

  Control.BeginInvoke(new Action(() => changetextmethod(); ));

}

catch

{}

αμα σου δινει exception.

 

   Αλλα οπως και να εχει η ολη λογικη σου δεν βγαζει νοημα. Καντο με τον σωστο τροπο και κανε bind το label.text σε ενα string.

 

public sealed class MyClass: INotifyPropertyChanged

{

   private static readonly MyClass instance = new MyClass();

   private MyClass() {}

 

   public static MyClass Instance get  return instance; }

 

   private string _text;

   public string Text

   {

      get { return this._text;

    }

      set

    {

      if (value == this._text) return;

      this._text = value;

      NotifyPropertyChanged("Text");

    }

 

  // INotifyPropertyChanged implementation

    public event PropertyChangedEventHandler PropertyChanged;

 

    private void NotifyPropertyChanged(String info)

    {

       var handler = PropertyChanged;

       if (handler == null) return;

       handler(this, new PropertyChangedEventArgs(info));

    }

}

 
Τωρα απλα θετεις σαν datacontext την MyClass και κανεις bind το Text στο Text του label. Οταν θελεις να το αλλαξεις κανεις
 
var kati = new MyClass();
kati.Text = txt;
Δημοσ.

WCFService.cs

    public class WCFService : Ταμείο, IWCFService

 

Αυτό δε βγάζει κανένα απολύτως νόημα και επίσης είναι ο λόγος που δεν υπάρχει περίπτωση να σου δουλέψει (στη λύση που λες δούλεψε, δεν αλλάζεις παρόλα αυτά κανένα label).

 

Εδώ λες ότι το WCFService είναι Ταμείο, το οποίο με τη σειρά του είναι Form. Είναι τέτοιο πράγμα το service? Φυσικά και όχι, και γι' αυτό λέω πως δε βγάζει νόημα.

 

Τώρα, εφόσον το έχεις δηλωμένο σαν Ταμείο, αυτό πάει να πει ότι η εφαρμογή σου έχει 2 Ταμείο: το ένα είναι το απλό (η φόρμα που βλέπεις) και το άλλο είναι το WCFService, το οποίο βέβαια παρότι είναι Form δεν εμφανίζεται ποτέ γιατί βέβαια κανείς δεν το μεταχειρίζεται σαν Form. Αντίστοιχα υπάρχουν και 2 label1, ένα μέσα σε κάθε Ταμείο. Που και πάλι, το ένα έχει δημιουργηθεί και το βλέπεις στην οθόνη ενώ το άλλο υπάρχει μόνο στα χαρτιά.

 

Τώρα όταν εσύ γράφεις μέσα στο WCFService label1, αυτό σημαίνει πως αναφέρεσαι στο label1 του service το οποίο είπαμε πως δεν έχει δημιουργηθεί καν, με αποτέλεσμα να παίρνεις το error που βλέπεις.

 

Αυτό που θα έπρεπε να κάνεις είναι

  1. Καμία σχέση το WCFService με ταμείο
  2. Κάπως να πεις στο service σου για το Ταμείο (τη Form)
  3. Όταν έρθει η ώρα BeginInvoke όπως είπαν τα παιδιά

Ένας από τους λιγότερο άσχημους τρόπους να κάνεις το 2 είναι:

public class WCFService : IWCFService
{
    private readonly Ταμειο tameio;
    public WCFService(Ταμείο form)
    {
        this.tameio = form;
       // όταν έρθει η ώρα, tameio.BeginInvoke(...)
    }
}

και

host = new ServiceHost(new WCFService(this), baseAddress);

Το ζητούμενο είναι να ξέρει το service σχετικά με το ταμείο. Εδώ το καταφέρνεις αυτό περνώντας το αντικείμενο του ταμείου σαν παράμετρο στον constructor του service.

 

Κλείνοντας, αυτό που καταλαβαίνω εγώ από τον παραπάνω κώδικα είναι ότι πήρες paste παράδειγμα από το internet(1) και προσπάθησες με "τυχαίες μεταβολές"(2) να το κάνεις να δουλέψει. Αυτό δεν παίζει. Ο κώδικας που έχεις είναι πολύ λίγος, ψάξτον να δεις πώς δουλεύει.

 

(1) Γι' αυτό και new ServiceHost(typeof(WCFService) -- στην πραγματικότητα ένας άλλος constructor θα σε βόλευε καλύτερα. Είναι 3 συνολικά, αλλά αν δεν πας να δεις δε θα το ξέρεις.

(2) WCFService : Ταμείο

Δημοσ.

Αυτό δε βγάζει κανένα απολύτως νόημα και επίσης είναι ο λόγος που δεν υπάρχει περίπτωση να σου δουλέψει (στη λύση που λες δούλεψε, δεν αλλάζεις παρόλα αυτά κανένα label).

 

Εδώ λες ότι το WCFService είναι Ταμείο, το οποίο με τη σειρά του είναι Form. Είναι τέτοιο πράγμα το service? Φυσικά και όχι, και γι' αυτό λέω πως δε βγάζει νόημα.

 

Τώρα, εφόσον το έχεις δηλωμένο σαν Ταμείο, αυτό πάει να πει ότι η εφαρμογή σου έχει 2 Ταμείο: το ένα είναι το απλό (η φόρμα που βλέπεις) και το άλλο είναι το WCFService, το οποίο βέβαια παρότι είναι Form δεν εμφανίζεται ποτέ γιατί βέβαια κανείς δεν το μεταχειρίζεται σαν Form. Αντίστοιχα υπάρχουν και 2 label1, ένα μέσα σε κάθε Ταμείο. Που και πάλι, το ένα έχει δημιουργηθεί και το βλέπεις στην οθόνη ενώ το άλλο υπάρχει μόνο στα χαρτιά.

 

Τώρα όταν εσύ γράφεις μέσα στο WCFService label1, αυτό σημαίνει πως αναφέρεσαι στο label1 του service το οποίο είπαμε πως δεν έχει δημιουργηθεί καν, με αποτέλεσμα να παίρνεις το error που βλέπεις.

 

Αυτό που θα έπρεπε να κάνεις είναι

  1. Καμία σχέση το WCFService με ταμείο
  2. Κάπως να πεις στο service σου για το Ταμείο (τη Form)
  3. Όταν έρθει η ώρα BeginInvoke όπως είπαν τα παιδιά

Ένας από τους λιγότερο άσχημους τρόπους να κάνεις το 2 είναι:

public class WCFService : IWCFService
{
    private readonly Ταμειο tameio;
    public WCFService(Ταμείο form)
    {
        this.tameio = form;
       // όταν έρθει η ώρα, tameio.BeginInvoke(...)
    }
}

και

host = new ServiceHost(new WCFService(this), baseAddress);

Το ζητούμενο είναι να ξέρει το service σχετικά με το ταμείο. Εδώ το καταφέρνεις αυτό περνώντας το αντικείμενο του ταμείου σαν παράμετρο στον constructor του service.

 

Κλείνοντας, αυτό που καταλαβαίνω εγώ από τον παραπάνω κώδικα είναι ότι πήρες paste παράδειγμα από το internet(1) και προσπάθησες με "τυχαίες μεταβολές"(2) να το κάνεις να δουλέψει. Αυτό δεν παίζει. Ο κώδικας που έχεις είναι πολύ λίγος, ψάξτον να δεις πώς δουλεύει.

 

(1) Γι' αυτό και new ServiceHost(typeof(WCFService) -- στην πραγματικότητα ένας άλλος constructor θα σε βόλευε καλύτερα. Είναι 3 συνολικά, αλλά αν δεν πας να δεις δε θα το ξέρεις.

(2) WCFService : Ταμείο

 

Σωστός ο παίχτης, Ευχαριστώ πολύ όλους παιδιά και εσένα Papakaliati ,δούλεψε. 

Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε

Πρέπει να είστε μέλος για να αφήσετε σχόλιο

Δημιουργία λογαριασμού

Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!

Δημιουργία νέου λογαριασμού

Σύνδεση

Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.

Συνδεθείτε τώρα
  • Δημιουργία νέου...