natürlich gibt es eine Lösung, aber du mußt hier einen ganz anderen Weg gehen.
Deine langandauernde Arbeit läßt du auf dem Webserver ausführen (z.B. in einer statischen Klasse), speicherst immer wieder den Status in einen Session zwischen und dein Usercontrol frägt zyklisch per Ajax den Status der Arbeit ab und gibt einen sinnvollen Text für den Benutzer aus.
Das mit AddOnPreRenderCompleteAsync brauchst du nicht. Denn meines Wissens kehrt der Seitenaufruf hier auch erst zum Browser zurück wenn deine Operation fertig ist. Also nützt dir das nichts.
Das erfordert paar Zeilen Programmieraufwand.
Ich kann dir morgen ein Beispiel Projekt senden.
ich kann dich beruhigen, beim MSSql hättest du das selbe Problem
Wie schon geschrieben, entweder du versucht die Zugriffe zu synchronisieren oder man baut wirklich ständig neue Verbindungen auf.
Das Synchronisieren bremst aber vermutlich die ganze Anwendung nur aus. Das mit Monitor.Enter / Exit würde auch nicht funktionieren, da es immer etwas dauert bis die Verbindung wirklich wieder bereitsteht.
Ansonsten gibts APIs mit denen du Office Dokumente erstellen und importieren und dann bearbeiten kannst, ohne ein Office auf dem Server installiert zu haben.
Ich habe mit den Produkten von[URL= http://www.aspose.com/]Aspose[/url] sehr gute Erfahrungen gemacht.
Auserdem kannst du die Dokumente komplett im Memory Stream bearbeiten, was mit dem ganzen Word über Com echt kompliziert ist.
ich habe auf einem SQLExpress Server 2 Datenbanken mit gleichem Inhalt.
Ich suche ein Tool mit dem ich tabellenweise von DB2 auf DB1 auf Knopfdruck kopieren kann.
Ich möchte nicht die ganze DB2 auf DB1 kopieren, sondern nur gewisse Tabellen.
Hintergrund:
Es gibt eine Version "Freigegeben" und eine "Vorbereitung".
Neue Benutzer z.B. werden in Freigeben gepflegt, Inhalte in Vorbereitung. Mit der herkömmlichen Backup Restore Funktion würde hier neue Benutzer überschrieben werden.
Kennt jemand ein Tool, darf ruhig auch kommerziell sein.
Vielen Dank.
Wenn du einen richtigen Postback anschließend machen würdest wäre das Panel auch sichtbar ;-)
Das liegt daran, das dein Panel pnlTest nicht in dem UpdatePanel enthalten ist.
Es wird nur der Teil der Seite neu gezeichnet welcher in dem UpdatePanel enthalten ist. Gibt 3 Möglichkeiten: Du verwendest keine Ajax, du packst dein pnlTest in das UpdatePanel oder du schreibst ein JavaScript mit dem du das Panel ein und ausblendest.
Für letzteres müßtest du in der btnTest_Click Methode mit ScriptManager.RegisterClientSript dein Javascript einschleusen damit das auch ausgeführt wird wenn Javascript dein UpdatePanel-Bereich in der Seite neu zeichnet.
Wenn diese Positionierung von pnlTest wirklich so gewünscht ist in der Seite, könntest du letzte Methode verwenden oder du verschiebst pnlTest in den UpdatePanel und positionierst es mit CSS an die gewünschte Position. Hier mußt du allerdings noch aufpassen. Bei mir war mal der Fall, wenn ich ein Panel von Anfang an Visible false setzte und es in einem UpdatePanel ist, wird beim Setzen auf Visible true das Panel nicht gezeichnet. Bin mir nicht sicher ob das ein Ajax Problem ist, oder nur bei meiner Konstelation ein Problem war. Hab mir dann ein Panel-Control gebaut, welches die Visible Eingenschaft durch eine CSS Eigenschaft "Display:none" ersetzt. D.h. beim Rendern wird immer das Panel in HTML Code übersetzt, aber ist halt über CSS ausgeblendet.
Möchtest du pnlTest von mehreren UpdatePanels aus aktuallisieren bleibt nur letzte Methode übrig.
So doll das Ajax auch ist, bei pixelgenaues Design kanns richtig umständlich werden wenn der Inhalt eines UpdatePanels sich auf verschiedene Bereiche in der Website dargestellt werden soll.
Eigentlich genauso wie Clients auf Methoden des Servers zugreifen.
Du Schreibst eine Klasse Client. Die muss ein bestimmtes Interface IClient implementieren. Da sind dann Methoden wie wie z.B. 'DataChanged()' enthalten.
Meldet sich der Client am Server an, gibt er eine Reference auf sich mit.
z.B. IServer.Connect(IClient client).
In der Liste speichert der Server die Referencen der Clients beim Anmelden.
Ändert ein Client Daten, z.B. ChangeData(IClient sender, MyData data)
dann weiß der Server wer Daten ändert. Du gehtst dann die Liste durch und rufst die MEthode DataChanged aller CLients auf. Über ne If Abfrage kannst du den Sender ja überspringen.
Ich habe wirklich Stunden geprüft, getestet und gedebuggt. Keine Antwort auf das Problem gefunden.
Warum 2 Connection-Objekte.
Es sind halt 2 Klassen mit je einem Connection-Objekte. Der Anwendungsfall benötigt halte beide Funktionalitäten. Die beiden Klassen laufen auch in verschiedenen Threads.
Es kam vor, das beide Connection-Objekte gleichzeitige eine DB-Anfrage gestartet haben.
Vielleicht gibts da ja im .Net-Framework. Keine Ahnung.
In den paar Zeilen Code und der Variablen sTableName (ist auch ReadOnly) ist eigentich kein Fehler.
Das Problem besteht nun nicht mehr. Habe das Verhalten des anderen Threads etwas geändert.
als Datenbank verwende die MSSQL2005Express Version.
In meiner Klasse habe ich folgende Methode um Daten aus der DB zu holen.
protected override void InitData()
{
dtData = new DataTable(this.sTableName);
SqlDataAdapter da = new SqlDataAdapter("select * from " + this.sTableName, new SqlConnection(sConnectionString));
da.Fill(dtData);
}
Weiterhin halte ich in meiner Klasse ein 2. SQLConnection Objekt welches in der selben DB auf eine andere Tabelle für abfragen zuständig ist.
Nun ist das Problem das beim 2. bis 3. Aufruf meiner Methode InitData plötzlich Datensätze aus einer anderen Tabelle. Genau genommen aus der Tabelle wofür ich das 2 SQLConnection-Objekt verwende.
Wie kann es dazu kommen?
Bin wirklich ratlos. Da auch bei InitData jedesmal ein neuer DataAdapter angelegt wird, mit neuem Connection-Objekt. Auch der String sTableName ändert sich nicht.
Dennoch bekomme ich falsche Datensätze.
Wie kann ich mein Usercontrol über den Pagerefresh hinaus erhalten?
Hallo, ich stand vor Kurzem vor dem selben Problem.
Hier mal meine Erfahrungen.
Du musst entweder deine Controls oder deine Daten irgendwo zwischenspeichern.
Hier gibt es verschiedene Wege.
Du packst deine Controls in einem Placeholder.
Beim Verlassen der Seite speicherst du den Inhalt (ControlCollection) des Placeholders in nem Session-Objekt ab.
Bei Laden der Seite holst du dir die Session und fügst die Items der Collection wieder dem Placeholder hinzu.
Das ganze funktioniert ganz gut. Hat aber einen Nachteil. Bei deinen UserControls wird kein PageLoad mehr ausgelößt. D.h. nachdem du die Controls aus der Session wieder in den Placeholder geschoben hast, war es das. Dazu unten mehr.
Wie kommen nun deine Events dennoch an das UserControl?
Du implementierst das IPostBackEventHandler Interface. Beim wiederherstellen rufst du dann RaisePostBackEvent() auf und übergibst request.Params["__EventArgument"].
Oder du schreibst dir ein Interface mit einer Page_Load(object sender, EventArgs e).
Dann rufst du nach dem Laden (PlaceHolder.Controls.Add()) selber die Page_Load auf. Wenn die Page_Load des UserControls aufgerufen wird, sollte das mit den Events wie gewohnt klappen.
Wenn die Page_Load nicht aufgerufen wird, habe ich festgestellt, dass mehrere Dinge dann oft nicht mehr richtige gehen. Z.B. die Selection bei einem DropDownFeld.
Hier ein bischen Code
public class PostbackSecurePlaceholder : System.Web.UI.WebControls.PlaceHolder, IPostBackEventHandler
{
#region IPostBackEventHandler Member
public void RaisePostBackEvent(string eventArgument)
{
foreach (Control co in this.Controls)
{
try
{
((IPostBackEventHandler)co).RaisePostBackEvent(eventArgument);
}
catch { }
}
}
#endregion
public void Store()
{
if (this.ID == null || this.ID.Length == 0)
throw new Exception("Field Id is required!");
if (Context.Session[this.ID] == null)
{
Context.Session.Add(this.ID, this.Controls);
}
else
{
Context.Session[this.ID] = this.Controls;
}
}
public void Restore()
{
if (Context.Session[this.ID] == null)
{
//hmm
}
else
{
ControlCollection coCol1 = ((ControlCollection)Context.Session[this.ID]);
while(coCol1.Count > 0)
{
this.Controls.Add(coCol1[0]);
}
Context.Session[this.ID] = this.Controls;
}
}
public void Restore(System.Web.HttpRequest request)
{
this.Restore(request.Params["__EventTarget"], request.Params["__EventArgument"]);
}
public void Restore(string eventTarget, string eventArgument)
{
if (Context.Session[this.ID] == null)
{
//hmm
}
else
{
ControlCollection coCol1 = ((ControlCollection)Context.Session[this.ID]);
while(coCol1.Count > 0)
{
try
{
//Diese IfAbfrage macht nur Sinn, wenn du ein Konzept zur Id vergabe hast, ansonsten ohne diesem If.
if (eventTarget != null && eventTarget.IndexOf(coCol1[0].ClientID) != -1)
{
((IPostBackEventHandler)coCol1[0]).RaisePostBackEvent(eventArgument);
}
//alternativ könnte ich mir auch sowas vorstellen (Das Interface müßte halt noch erstellt werden.
//Dann ersparrt man sich das RaisePostBackEvent und dann das Herausfieseln wohin das Event soll (wie oben versucht zu beschreiben).
//Handhabe es mittlerweilse so, ist ein bischen älterer Code hier.
//((IPerformPageLoadHandler)coCol1[0]).Page_Load(this, eventArgument));
}
catch
{
}
this.Controls.Add(coCol1[0]);
}
Context.Session[this.ID] = this.Controls;
}
}
}
So gehst du dann damit in der Seiten-Klasse damit um
UserControls speichern
protected override void OnPreRender(EventArgs e)
{
this.placeholder1.Store();
...
UserControls wiederherstellen
protected override void OnInit(EventArgs e)
{
this.placeholder1.Restore(this.Request);
...
//UserControls hinzufügen
placeholder1.Controls.Add( this.Page.LoadControl("MYControl.ascx") );
Danke für das ClearSelection().
Schon wieder eine Zeile Code gesparrt.
Problem ist auch behoben. War ein dummer Fehler von mir.
Das auslösende Event kam von einem ContextMenu. Dieses wurde von mehreren DataGridViews verwendet.
Bei der Ereignisbehandlung habe ich auf dann die SelectedRows vom falsche dgv abgerufen.
Was mich jetzt noch ein wenig wundert ist, das die Seletion bei anderen dgv auch aktiv war. Obwohl ich da garnichts geklickt habe.
Die beiden dgv hatte die selbe DataSource, eine DataView. Anscheinend wird die Selection im Objekt DataView gespeichert.
Wenns ganz einfach sein soll, würde ich Webservices nehmen.
Für eine bidirektionale Kommunikation würde das ganze über Corba machen.
Falls dir das nichts sagt, ist ähnlich dem .NetRemoting.
Habs zwar mit .Net noch nicht gemacht, aber ich denke da gibts schon Produkte die Bibliotheken und Tools beinhalten um die passenden Proxy-Klassen zu erstellen.
ich verwende System.Data.SqlClient.SqlTransaction.
Ich werds dann mal mit System.Transactions versuchen.
Das seltsamme ist wirlich, das dieses Vorgehen bis vor einer Weile noch funktioniert hat. Die Datenbank war zwischenzeitlich auf einem anderen Server. Kann es an Einstellungen des DB-Servers oder der Datenbank liegen?
Nachtrag:
leider kein Erfolg. Ich vermute mal da hat der SQL Server irgendein Problem.
ich habe ein echt seltsammes Problem.
Ich führe mehrere DB-Aktionen in einer Transaktion aus.
In einer Schleife werden ständig Insert-Commands ausgeführt und anschließend ein "Select @@Identity".
Mein Problem ist, wenn ein "Select @@Identity" ausgeführt wird, alle weiteren Insert-Befehle immer wieder die in die selbe Zeile in der Tabelle schreiben. Natürlich ist die neue LastInsertId wieder der Wert wie bei der ersten.
In der Tabelle steht zum Schluss die Werte des letzten Insert-Befehls aus der Schleife.
Begin Transaction
Insert into A ... value = 100...
Select @@Identity -> gibt mir z.B. 10
Insert into A ... value = 200 ...
Select @@Identity -> bringt wieder die 10 zurück
Transaction.Commit()
...
Select * from A where... -> Ergebnis ist der letzte Eintrag, im Bsp. die 200.
An was könnte das liegen?
Frage ich nicht die LastInsertId ab, funktioniert alles.
Ja, die Queries werden im Code zusammen gebaut. Ich hatte vorher diese Problematik auch mit 2 oder mehreren Abfragen hintereinander gelößt.
Nur war die Performance einfach misst. Habe festgestellt wenn ich die Komplexität in den SQL Server ausagere, eine deutlich bessere Gesamtperformance erhalte.
Danke, mit der Semaphore ManuelResetEvent konnte ich das lösen.
War nur etwas tricky die Startzustände festzulegen, da nicht vorherzusagen war welcher Thread zu erst gestartet wird und beide gleichberechtig sind.