[ASP.NET C#]Server-side Word gebruiken

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

  • Walance
  • Registratie: September 2005
  • Laatst online: 17-09 17:03

Walance

Hm.. wat zal ik hier schrijven

Topicstarter
Het probleem
Wij hebben verschillende website's die gebruik maken van ons CMS/DMS, hierbij hebben we een HTMLEditor gemaakt zodat gebruikers gemakkelijk zelf de content van hun site kunnen aanpassen.
Nu willen sommige gebruikers graag dat ze complete Office Word en OpenOffice Writer documenten kunnen importeren via de website en zo deze gemakkelijk op hun site kunnen zetten en hier zit nu het probleem, hiervoor willen we Microsoft.Office.Interop.Word gebruiken voor Word om het document daarmee te openen en op te slaan als HTML, maar daar lopen tegen een aantal problemen aan.

De HTML die Word maakt is natuurlijk erg vies en wil je nooit op een website hebben, maar daarvoor gebruiken we HTMLTidy, om de HTML op te schonen, maar daar gaat dit topic niet over.

Voordat jullie meteen gaan zeggen dat Office hier niet voor gemaakt is enzo, dat weten we, we hebben ook dit artikel gelezen, maar het moet toch wel kunnen?

Op zoek naar oplossingen
Toen we het in het begin hadden gemaakt leek het allemaal goed te werken, documenten werden netjes geopend, opgeslagen als HTML en gesloten. Maar... dit was tijdens het ontwikkelen en testen in Visual Web Developer Express 2008, welke zijn eigen webserver (Visual Studio Development Server) heeft en standaard ook gebruikt.

Daarna zijn we gaan testen in IIS, maar daar kwam dus het grote probleem, daarmee werkte het niet. Word werd wel opgestart, maar daarbij kregen we een 'Access denied' foutmelding bij Word en 'Server execution failed' bij Writer.

Hierna zijn we dus gaan onderzoeken wat het probleem kan zijn en het bleek al snel dat het een rechten probleem is. IIS maakt gebruik van een gebruiker ASPNET, welke heel beperkte rechten heeft. Visual Studio Development Server gebruikt het account waarmee je bent ingelogd (welke, in mijn geval, administrator rechten heeft). Toen had ik geprobeerd om mijn eigen gebruikers-account te gebruiken voor ASP.NET, dmv de impersonate instelling van de web.config en toen werkte het ook met IIS.

Daarna heb ik een nieuwe gebruiker gemaakt (genaamd test) in Windows en die administrator gemaakt, om te testen, en die in ASP.NET gebruikt, dit werkte ook. Omdat het natuurlijk niet slim is om gebruik te maken van een account met administrator rechten voor ASP.NET is dit geen goede oplossen en dus gingen we verder zoeken naar wat voor rechten meneer test moet hebben om dit te kunnen.

We kwamen al snel iets tegen dat je dcomcnfg moest gebruiken om aan "Microsoft Office Word 97 - 2003 document" de gebruikers die gebruikt worden door IIS toe te voegen zodat ze die mogen opstarten. We hebben dat toen gedaan door bij "Launch and Activation Permissions" en "Access Permissions" de volgende gebruikers toe te voegen: ASPNET, IUSR_[MACHINENAAM] en IWAM_[MACHINENAAM] en deze "local launch" en "local activation" rechten te geven (remote zou niet nodig moeten zijn, maar hebben we voor de zekerheid ook geprobeerd en werkte ook niet). Hiermee was de "Access denied" melding bij het aanroepen van Word weg, maar veel verder dan dat kwam het niet, het proces "WINWORD.exe" werd geopend, maar leek verder niets te doen, bij het debuggen bleek dat het bleef hangen op het volgende stukje:
C#:
1
2
3
4
5
WordApp.Documents.Open(
ref lvFileName, ref lvUnknown, ref lvUnknown, ref lvUnknown,
ref lvUnknown, ref lvUnknown, ref lvUnknown, ref lvUnknown,
ref lvUnknown, ref lvUnknown, ref lvUnknown, ref lvUnknown,
ref lvUnknown, ref lvUnknown, ref lvUnknown, ref lvUnknown);

Hoe lang we ook wachtte, er gebeurde niets en het bleef bezig met laden, het leek erop dat Word ergens op wachtte, bijvoorbeeld op een actie van de gebruiker.

We hebben "Full control" rechten gegeven aan de map waarin documenten geüpload worden en welke vervolgens worden geopend. Ook hebben we geprobeerd om dezelfde rechten op "winword.exe" in de map "C:\Program Files\Microsoft Office\Office12" te zetten, maar dat wilde ook niet helpen.

Daarna hebben we nog verschillende andere dingen gevonden en geprobeerd, maar omdat dit topic al erg lang begint te worden en ik niet alles meer precies weet, laat ik dat er maar even uit, op één ding na:

Andere aanpak / idee
Als laatste kregen we nog het idee om een console programma te maken die op dezelfde manier het openen en opslaan van documenten doet regelen, dit gingen we dan aanroepen via ASP.NET op de volgende manier:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public string GetHtml(string pvConvertedLocation, string pvFileLocation, string pvUsername, string pvPass, string pvDomain)
{
    string lvHTML = "";

    System.Diagnostics.Process lvProcess = new System.Diagnostics.Process();

    lvProcess.StartInfo.FileName = Server.MapPath(@"bin\ParseDoc.exe");
    lvProcess.StartInfo.Arguments = pvConvertedLocation + " " + pvFileLocation;
    lvProcess.StartInfo.UseShellExecute = false;
    lvProcess.StartInfo.RedirectStandardOutput = true;
    lvProcess.StartInfo.Domain = pvDomain;
    lvProcess.StartInfo.UserName = pvUsername;
    lvProcess.StartInfo.RedirectStandardInput = true;
    lvProcess.StartInfo.RedirectStandardError = true;
    lvProcess.StartInfo.RedirectStandardOutput = true;

    Char[] lvCharArray = pvPass.ToCharArray();
    System.Security.SecureString lvSecurePassword = new System.Security.SecureString();
    foreach (char lvChar in lvCharArray)
    {
        lvSecurePassword.AppendChar(lvChar);
    }
    lvProcess.StartInfo.Password = lvSecurePassword;

    try
    {
        if (lvProcess.Start())
        {
            lvHTML = lvProcess.StandardOutput.ReadToEnd();
        }
        else
        {
            lvHTML = "fout";
        }
    }
    catch (Exception lvException)
    {
        lvHTML = lvException.ToString();
    }

    return lvHTML;
}

Wij dachten dus om op deze manier het probleem te omzeilen, omdat we dan de console applicatie aanroepen en die applicatie laten draaien met een administrator account, dat zou in ieder geval een stuk veiliger moeten zijn dan heel ASP.NET als administrator te laten draaien (of vergissen we ons hierin?). Helaas werkte dit ook niet, we kregen eerst een "Application failed to initialize properly" melding, na wat zoeken kwam ik dit artikel tegen, waarmee ik die melding heb kunnen oplossen. Hierna kregen we weer het probleem dat het proces blijft hangen op de Open functie van Microsoft.Office.Interop.Word.

En nu..?
Er zijn zoiezo nog dingen waar we rekening mee moeten houden als we dit ooit werkend krijgen, zoals wat er gaat gebeuren als er meerdere dit tegelijk gebruiken (hoewel dit waarschijnlijk niet gaat gebeuren)?

Wat zien wij over het hoofd? Het moet wel mogelijk zijn lijkt me? Want het werkt wel als we de gebruiker die IIS gebruikt toevoegen aan administrators, maar dat is natuurlijk een slecht idee... Zijn er nog ergens bepaalde rechten in Windows die we moeten geven of is er nog iets anders aan de hand?

Nog een laatste ding
Alternatieven geven omdat Office zo eigenlijk niet gebruikt hoort te worden mag natuurlijk altijd, maar ga au.b. niet flamen door alleen te zeggen dat dit niet goed is en we ermee moeten stoppen of zo.

[ Voor 1% gewijzigd door Walance op 07-09-2009 16:14 . Reden: foute link ]


Acties:
  • 0 Henk 'm!

  • L-VIS
  • Registratie: April 2005
  • Nu online
Misschien begrijp ik je niet helemaal goed, maar je wilt dus dat op de client Word wordt opgestart en zodoende de gebruiker Html kan editten?

Als het antwoord op deze vraag "ja" is, dan vrees ik dat je het model Client/Server nog niet helemaal begrepen hebt en het steeds toevallig goed gaat omdat client en server fysiek dezelfde machines zijn.

@Conquerer:
Het verhaal hieronder is een stuk duidelijker. Ik dacht echt dat je iets heel erg vreemds wilde :)

Ik vind de oplossing van AB.NET eigenlijk wel netjes. Eventueel zou je dit met een een service oplossen. Die zou je kunnen laten luisteren naar een directoryChanged (oid) event.

[ Voor 29% gewijzigd door L-VIS op 07-09-2009 14:51 ]


Acties:
  • 0 Henk 'm!

  • Walance
  • Registratie: September 2005
  • Laatst online: 17-09 17:03

Walance

Hm.. wat zal ik hier schrijven

Topicstarter
Nee, dat wil ik natuurlijk niet, ik snap dat dat niet gaat en ik begrijp het model Client/Server goed.
Het gaat er hierom dat ze een Word document uploaden, vervolgens wordt op de server het bestand in een bepaalde map gezet. Dit bestand wordt dan, weer op de server, geopend met Word. Daarna gaat Word het, op de server, opslaan als HTML. Als laatste wordt dan het opgeslagen HTML bestand ingelezen, wordt de HTML opgeschoond met HTMLTidy en teruggeven als een string. Vervolgens wordt de HTML teruggeven aan de client, waarna de client het eventueel verder kan bewerken in de HTML editor.

Sorry als dit onduidelijk was.

[ Voor 6% gewijzigd door Walance op 07-09-2009 14:43 . Reden: zinnen klopte niet helemaal.. ]


Acties:
  • 0 Henk 'm!

  • AB.NET
  • Registratie: April 2008
  • Niet online
Heb zoiets wel eens gedaan, door gebruik te maken van impersonation. De interop code wordt dan uitgevoerd met de credentials van een andere user.
Dit was echter voor een interne webapplicatie met weinig gebruikers.
Het lijkt me niet wenselijk deze oplossing voor een publieke website te gebruiken i.v.m. security en performance.

Kan je het document via asp.net niet klaarzetten voor een los proces met meer rechten, dit proces kan de word documenten oppakken en verwerken, en eventueel een seintje teruggeven aan de webapp als de file klaar staat.

voorbeeld van impersonation code, in vb.net

[ Voor 19% gewijzigd door AB.NET op 07-09-2009 14:55 . Reden: linkje toegevoegd ]


Acties:
  • 0 Henk 'm!

  • Walance
  • Registratie: September 2005
  • Laatst online: 17-09 17:03

Walance

Hm.. wat zal ik hier schrijven

Topicstarter
Bedankt voor je idee, dat kunnen we inderdaad wel eens proberen, we gebruiken nu al wel een aparte applicatie, maar die werd nog steeds via ASP.NET aangeroepen en draaide daardoor waarschijnlijk ook in hetzelfde proces.

Alleen vraag ik me nog af hoe de client dan kan weten wanneer die losse applicatie klaar is, deze moet dan blijven luisteren op één of andere manier.

Maar nog wel iets anders:
Een collega van mij had een windows service gemaakt die dan Word aanroept met wat we willen doen. Deze draait dus wel apart en wordt niet gestart/gestopt door ASP.NET, maar werd wel direct aangeroepen via ASP.NET en keek dus niet in een map of zo. Hiermee hadden we precies hetzelfde probleem.

Is dit niet eigenlijk ongeveer hetzelfde als wat AB.NET voorstelde, volgens ons zou dat dan niet ook echt een apart proces moeten zijn, met zijn eigen rechten?

Acties:
  • 0 Henk 'm!

  • AB.NET
  • Registratie: April 2008
  • Niet online
Een service draait onder het system account, en heeft dus ook beperkte rechten.
Als je het via een service wil doen moet je alsnog gebruik maken van impersonation, of de service onder een ander account laten draaien.

Om de applicatie met elkaar te laten communiceren zijn er veel verschillende oplossing, zoek maar eens op Inter-process communication. Je kan het zo ingewikkeld maken als je zelf wil.
1 van de eenvoudigste manieren is een tabel in een gezamenlijke database die beide applicaties pollen.

Acties:
  • 0 Henk 'm!

Verwijderd

De service draaide onder een admin account welke ook gebruikt is om via webconfig impersonation te testen.
Daar werkte het maar als je een service onder admin draait en dan via asp.net aanroept (via remoting in dit geval)
dan krijgen we nog steeds hetzelfde probleem dat Word bij de Documents.Open blijft hangen.

Acties:
  • 0 Henk 'm!

  • jip_86
  • Registratie: Juli 2004
  • Laatst online: 17-09 15:19
En een losse service die let op .doc bestanden in map A, en ze dan weer neerzet in map B als html? Als het goed gaat is de .doc weg in map A en terug als html in map B. Die service draait dan helemaal los van ASP.Net.

[ Voor 12% gewijzigd door jip_86 op 07-09-2009 19:49 ]


Acties:
  • 0 Henk 'm!

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 13-09 00:05
Het idee dat je Word macro's op je server uitvoert zou elke sysadmin tot wanhoop moeten drijven. jip_86's idee kan wel. Je moet dan net zoals ASP een aparte service maken, en die service moet onder een account draaien met absoluut minimale rechten. Dus leesrechten in 1 directory en schrijfrechten in 1 andere directory, leesrechten op de standaard Windows directory en de Office directory, en verder niets.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


Acties:
  • 0 Henk 'm!

  • Walance
  • Registratie: September 2005
  • Laatst online: 17-09 17:03

Walance

Hm.. wat zal ik hier schrijven

Topicstarter
Iets onder een ander account laten draaien met minimale rechten werkt juist niet, dat is het hele probleem....

We zullen in ieder geval nog proberen om een service te maken die helemaal lost draait en vervolgens te pollen, ik laat dan nog wel weten hoe dat is gegaan.

Acties:
  • 0 Henk 'm!

  • Walance
  • Registratie: September 2005
  • Laatst online: 17-09 17:03

Walance

Hm.. wat zal ik hier schrijven

Topicstarter
Sorry voor de late reactie en om het topic omhoog te halen, maar misschien dat er nog mensen geïnteresseerd zijn in hoe het is gegaan. Er waren wat andere projecten tussendoor gekomen die eerst af moesten en daarom had ik even geen tijd om hier mee verder te gaan.

Maar ik heb het nu eindelijk werkend gekregen, zoals al was voorgesteld heb ik een windows service gemaakt die een bepaalde map pollt d.m.v. een FileSystemWatcher in .NET.

De gebruiker kan via de website een .doc of .docx bestand uploaden, deze wordt vervolgens geplaatst in de juiste map op de server. De service ziet vervolgens dat er een nieuw bestand is gemaakt en pakt deze op om het bestand te openen met Word en opslaan als HTML in een andere map, als dat goed gegaan is wordt het originele bestand verwijderd.

Terwijl de service dit aan het doen is, draait de pagina-aanvraag van de gebruiker nog, toen de gebruiker het document had geselecteerd en het formulier verstuurd had, deze blijft kijken in de map waar het HTML bestand moet komen, totdat het bestand er in gezet wordt of totdat er 30seconden voorbij zijn gegaan (langer dan dat zou het nooit moeten duren, dan is er iets fout gegaan en dan krijgt de gebruiker een nette foutmelding, ipv dat de gebruiker nooit een antwoord van de server terug krijgt). Vervolgens wordt de inhoud van het nieuwe HTML bestand ingelezen, wordt er een HTML-tidy overeen gedraait en wordt de uiteindelijke HTML in de HTML-editor geplaatst. Nu kan de gebruiker nog eventueel wat aanpassen in de HTML-editor en het daarna opslaan.

Er waren nog wat probleempjes met dit in het begin, zoals dat de FileSystemWatcher meteen ziet zodra er een bestand bij geplaatst wordt, maar het kan dan zijn dat het neerzetten van het bestand dan nog niet klaar is. Dit hebben we opgelost m.b.v. een while(true), daarin wordt geprobeerd om het bestand in te lezen, als dit niet lukt wordt er een Thread.Sleep(1000) uitgevoerd om 1 seconde te wachten en daarna gaat de while weer verder. Als het uiteindelijk lukt om het bestand te openen (of als het 30 keer gefaald heeft), dan wordt een break uitgevoerd en wordt de rest gedaan.

Er moet nog veel getest worden, maar we hebben nu in ieder geval iets wat werkt. Bedankt voor jullie hulp in ieder geval.

Nu nog een keer OpenOffice werkend krijgen op deze manier, want tot nu toe is het daarvoor nog steeds niet gelukt.

Acties:
  • 0 Henk 'm!

  • R4gnax
  • Registratie: Maart 2009
  • Laatst online: 06-09 17:51
Mijn € 0,02 zou hier zijn dat het feit dat je door x aantal hoepels moet springen om dit op een enigzins fragiele manier aan elkaar gelijmd te krijgen al een duidelijke indicatie zou moeten zijn dat je iets verkeerds aan het doen bent. Nooit gehoord van Bad Smells? Wel: dit stinkt harder dan een open riool in de zinderende zon.

Voor die - Sorry dat ik het zeg, maar het is nu eenmaal zo. - achterlijke gebruikers die per sè Word documenten willen importeren als webpagina, kun je ook een instructie achterlaten om eerst hun troep in Word als HTML op te slaan en die brij te uploaden i.p.v. het Word document. Vervolgens hoef je dan op de server alleen nog maar Tidy te draaien. Je dekt op die manier ook gelijk OpenOffice af, of uitvoer uit andere programma's die 'export naar HTML' ondersteunen. (Uiteraard moet je nog wel iets verzinnen voor ondersteunende resources zoals plaatjes.)

Daarnaast: als je inderdaad 'dat artikel' gelezen zou hebben, zou je weten dat server-side Office automation volgens Microsoft's licentie niet eens toegestaan is. Het is niet eens grijs gebied; het is ronduit zwart gebied, tenzij jij aan kunt tonen dat de enige client systemen die van de serverside automation gebruik kunnen maken gekoppeld zitten aan een geldige Office licentie. (En dat gaat je never nooit lukken.) Ik hoop voor je dat je niet een audit op je dak gaat krijgen, want dan hang je.

[ Voor 9% gewijzigd door R4gnax op 30-10-2009 17:38 ]


Acties:
  • 0 Henk 'm!

  • MrBucket
  • Registratie: Juli 2003
  • Laatst online: 29-10-2022
Wellicht dat voor TS of andere geinteresseerden Office Open XML een goed alternatief biedt om te voorkomen dat je met COM / Interop spul aan de slag moet.

Blogger Eric White is op dit moment met een soortgelijk project bezig: Transforming Open XML Word-Processing Documents to XHtml
Pagina: 1