<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Janne Mattila's blog : Excel Services</title><link>http://blogs.msdn.com/jannemattila/archive/tags/Excel+Services/default.aspx</link><description>Tags: Excel Services</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>Dynamically create static Excel files for Excel Service</title><link>http://blogs.msdn.com/jannemattila/archive/2007/11/06/dynamically-create-static-excel-files-for-excel-service.aspx</link><pubDate>Tue, 06 Nov 2007 20:07:50 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:5939871</guid><dc:creator>jannemattila</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/jannemattila/comments/5939871.aspx</comments><wfw:commentRss>http://blogs.msdn.com/jannemattila/commentrss.aspx?PostID=5939871</wfw:commentRss><description>&lt;p&gt;Excel Services is pretty nice for displaying Excel files over the network. But if you're developing Excel Services solution for the first time you might first think of the limitations or something that forces you to build your overall solution in certain way. So I thought I'll write little bit about my idea about creating dynamically static Excel files. This might be something that you could be interested in... or not :-) It of course depends on the solution that you need to build. I just want to give you few ideas that you can use in your own projects. Okay here we go!&lt;/p&gt; &lt;h3&gt;&lt;/h3&gt; &lt;h3&gt;We want...&lt;/h3&gt; &lt;ol&gt; &lt;li&gt;...to use 2 different languages (Finnish and English)  &lt;li&gt;...have static texts in Excel that needs to be translatable  &lt;li&gt;...use pivottables  &lt;li&gt;...export data into .xlsx and to .csv (and possibly to some other formats as well)  &lt;ul&gt; &lt;li&gt;And the end user cannot see any formulas in their exported files&lt;/li&gt;&lt;/ul&gt; &lt;li&gt;...filter the data from UI &lt;ul&gt; &lt;li&gt;Translation for that: We need to pass parameters to the database query&lt;/li&gt;&lt;/ul&gt; &lt;li&gt;...have easily maintainable system (=minimize the amount of Excels)  &lt;li&gt;...flexible solution. So if we later want more complex scenarios this needs to be supported in your solution.  &lt;li&gt;...performance performance performance (but no extra costs!)  &lt;ul&gt; &lt;li&gt;But we only update the incoming data quite rarely&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;Okay... list is quite long and I need to discuss a little bit about those demands. &lt;/p&gt; &lt;p&gt;1 to 3) Supporting more than one language can be issue if your data contains texts that needs to be translated. Also pivottable column names, captions and total captions needs to be translated. So translating static texts is easy compared to that :-)&lt;/p&gt; &lt;p&gt;4) Exporting to .xlsx is easy. Just use Excel Services API and retrieve "snapshot" and you're good to go. But if you want to convert it to other formats then you need to do some extra work.&lt;/p&gt; &lt;p&gt;5) You can use filtering but if you think of 8) you just can't do filtering of 2 million rows if you just want to view 50 rows... that would kill the performance. So since you need to think of performance you probably want to pass parameters to your database queries. If plan to get your relational data into your Excel using Office Database Connection (ODC)&amp;nbsp; you cannot unfortunately use parameters since querytext will be "&lt;em&gt;hardcoded&lt;/em&gt;" into the ODC. Of course you can achieve that with multiple ODC files but it could create mess. You can store those in Data Connection Library (DCL) to ease up the maintenance pain but still it's quite challenging to do that (=my personal opinion). And if you then think of the 6) you don't want to create maintenance hell. And of course if it gets too complicated you would most likely have issues with ODC approach. But if you use OLAP you could manage with only one ODC.&lt;/p&gt; &lt;p&gt;6) You don't want to have 1,5 million different files and then update them manually? Okay... I'll get the picture.&lt;/p&gt; &lt;p&gt;7) I know that predicting future is hard so let's create solution that is flexible enough so that you can extend it in many ways. I don't want to give limitations to your future needs.&lt;/p&gt; &lt;p&gt;8) So you don't want to buy 5 new servers with lot of processors? What about memory then... it's cheap? So that's okay... let's try to create as static files as we only can. This way we can use "&lt;em&gt;memory over CPU&lt;/em&gt;" approach as much as possible. And creating stuff in cache before users are going to use the system would be nice.&lt;/p&gt; &lt;p&gt;I'm ready to go to next phase and show you my example that I have created.&lt;/p&gt; &lt;h3&gt;Implementation of my solution&lt;/h3&gt; &lt;p&gt;Phases:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;Create database for the example  &lt;li&gt;Create template Excel file  &lt;ul&gt; &lt;li&gt;This is then used to create the "static copy instance"&lt;/li&gt;&lt;/ul&gt; &lt;li&gt;Create SharePoint structure for the demo  &lt;li&gt;Create custom web part that hosts EWA and fills the other requirements as well  &lt;ul&gt; &lt;li&gt;Exports to different file formats  &lt;li&gt;Filter the query from UI  &lt;li&gt;Translate texts that are needed in order to get the file in users native language&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ol&gt; &lt;h4&gt;&lt;strong&gt;1. Create database for the example&lt;/strong&gt;&lt;/h4&gt; &lt;p&gt;In my example I'll use legendary AdventureWorks database :-) (I know that for some developers this itself will cause some hatred towards me ;-)&lt;/p&gt; &lt;p&gt;I did minor changes to the AdventureWorks data since I want my demo to support English and Finnish. I modified French culture to be Finnish culture and then modified the texts in description to be example same as the name (so that I'll can demonstrate the translations in database layer) (Note: I didnt' change the &lt;em&gt;ProductModel&lt;/em&gt; translation since I want to "translate" it in my code). &lt;/p&gt; &lt;p&gt;My plans is to demonstrate product data. Here's an example of the data:&lt;/p&gt; &lt;div class="wlWriterSmartContent" id="scid:6960CE03-38FC-44df-87D4-FA4540212B06:89098b14-74fc-43bd-b0c9-4e4230bce981" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;img src="http://blogs.msdn.com/photos/jannemattila/images/5831110/original.aspx" alt="" style="width:580px; height:168px;" /&gt;&lt;/div&gt; &lt;p&gt;From that data you can easily see that I'm going to use culture info to get the correct data to my Excel. Of course you could create your own SQL/stored procs to handle translations as you wish. &lt;/p&gt; &lt;p&gt;&lt;strong&gt;2. Create template Excel&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;Now I'm going to create Excel that uses previously modified data. Since my plan is to dynamically fill the Excel with data I'm just going to create "&lt;em&gt;almost empty template&lt;/em&gt;" that will be placeholder for the real data. Here are screenshots from my &lt;em&gt;MyEWA.xlsx&lt;/em&gt; Excel file:&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;div class="wlWriterSmartContent" id="scid:6960CE03-38FC-44df-87D4-FA4540212B06:a62d8358-04c7-47e6-985b-8130ac82be19" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;img src="http://blogs.msdn.com/photos/jannemattila/images/5919972/original.aspx" alt="" style="width:497px; height:395px;" /&gt;&lt;/div&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;em&gt;Display&lt;/em&gt;-sheet has static text in &lt;em&gt;A2&lt;/em&gt; and then it has Pivottable that retrieves data from the &lt;em&gt;Data&lt;/em&gt;. If you're really sharp you probably noticed that row 5 is missing from the &lt;em&gt;Display&lt;/em&gt;-sheet... I'll come to that later.&lt;br&gt;&lt;/p&gt; &lt;div class="wlWriterSmartContent" id="scid:6960CE03-38FC-44df-87D4-FA4540212B06:95af23cd-71ad-4ede-bf55-f2732c1708e8" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;img src="http://blogs.msdn.com/photos/jannemattila/images/5920286/original.aspx" alt="" style="width:496px; height:395px;" /&gt;&lt;/div&gt;&lt;br&gt;&lt;em&gt;Data&lt;/em&gt;-sheet contains Header row and then it contains 1 data row. This data row can been seen from the pivottable in the &lt;em&gt;Display&lt;/em&gt;-sheet.  &lt;p&gt;&lt;/p&gt; &lt;p&gt;Third sheet is &lt;em&gt;Parameters&lt;/em&gt; and in this example I'll only use it to pass &lt;em&gt;Culture&lt;/em&gt; to the Excel:&lt;br&gt;&lt;/p&gt; &lt;div class="wlWriterSmartContent" id="scid:6960CE03-38FC-44df-87D4-FA4540212B06:31a23842-fe5c-4018-8c24-add68a395b62" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;img src="http://blogs.msdn.com/photos/jannemattila/images/5920590/original.aspx" alt="" style="width:497px; height:392px;" /&gt;&lt;/div&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;So if we now take closer look at the &lt;em&gt;Display&lt;/em&gt;-sheet and see the formula in cell &lt;em&gt;A2&lt;/em&gt;:&lt;/p&gt; &lt;div class="wlWriterSmartContent" id="scid:6960CE03-38FC-44df-87D4-FA4540212B06:f7f20a7d-c44c-46b2-9c91-1a16f76b6755" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;img src="http://blogs.msdn.com/photos/jannemattila/images/5920691/original.aspx" alt="" style="width:796px; height:118px;" /&gt;&lt;/div&gt; &lt;p&gt;&lt;em&gt;A2&lt;/em&gt; cell contains following formula:&lt;/p&gt; &lt;p&gt;&lt;em&gt;=IF(Parameters!B1="en-US";"Here is report about products.";"Tässä on raportti tuotteista")&lt;/em&gt;&lt;/p&gt; &lt;p&gt;It's pretty easy to understand that if the &lt;em&gt;B1 &lt;/em&gt;cell in &lt;em&gt;Parameters&lt;/em&gt;-sheet is set to &lt;em&gt;en-US&lt;/em&gt; then the text will be "&lt;em&gt;Here is report about products&lt;/em&gt;"&lt;em&gt;.&lt;/em&gt; and if it isn't then "&lt;em&gt;Tässä on raportti tuotteista&lt;/em&gt;" text will appear in the cell (latter text is same as the English one but in Finnish :-). By now probably everybody knows already that we're going to change the value in &lt;em&gt;Parameters!B1&lt;/em&gt; dynamically... and use it to translate the static texts inside Excel into correct language. &lt;/p&gt; &lt;p&gt;This same can be achieved if you dynamically copy text over specific cells. I have example of that in my code but it's commented because I didn't use it in my solution. But if you need to check this approach you can create new sheet i.e. &lt;em&gt;Translations&lt;/em&gt; and have three columns &lt;em&gt;Location, Text in fi-FI&lt;/em&gt; and &lt;em&gt;Text in en-US.&lt;/em&gt; And then dynamically go through those translations and copy text to correct location i.e. &lt;em&gt;Data!A5&lt;/em&gt;.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;3. Create SharePoint structure for the demo&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;SharePoint site structure is following in my demo (in your case you can have whatever names... I just used culturenames to make this as simple as possible):&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Example portal  &lt;ul&gt; &lt;li&gt;en-US:  &lt;ul&gt; &lt;li&gt;default.aspx  &lt;li&gt;MyEWA.aspx&lt;/li&gt;&lt;/ul&gt; &lt;li&gt;fi-FI  &lt;ul&gt; &lt;li&gt;default.aspx  &lt;li&gt;MunEWA.aspx&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Obviously &lt;em&gt;en-US&lt;/em&gt; is site that has regional settings (Site settings-&amp;gt;Site administration: Regional settings) set to &lt;em&gt;English&lt;/em&gt; locale:&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;div class="wlWriterSmartContent" id="scid:6960CE03-38FC-44df-87D4-FA4540212B06:805ecaa4-a374-48b1-a2a0-5b2db8470a78" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;img src="http://blogs.msdn.com/photos/jannemattila/images/5921172/original.aspx" alt="" style="width:527px; height:169px;" /&gt;&lt;/div&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;And &lt;em&gt;fi-FI&lt;/em&gt; site is set to &lt;em&gt;Finnish &lt;/em&gt;locale.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;4. Create custom web part that hosts EWA and fills the other requirements as well&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;Now we're ready to show the user interface for our solution. My solution is &lt;em&gt;MyEWA&lt;/em&gt; web part that contains all the necessary controls and functionality this solution needs. As always my I'll cut short in the UI implementation. I'll just add few buttons and dropdown but no fancy look &amp;amp; feel. &lt;/p&gt; &lt;p&gt;UI in &lt;em&gt;MyEWA.aspx&lt;/em&gt;:&lt;/p&gt; &lt;div class="wlWriterSmartContent" id="scid:6960CE03-38FC-44df-87D4-FA4540212B06:e25a8f6c-c5ba-4302-93fb-1ff60be2ca08" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;img src="http://blogs.msdn.com/photos/jannemattila/images/5929401/original.aspx" alt="" style="width:675px; height:368px;" /&gt;&lt;/div&gt; &lt;p&gt;UI in &lt;em&gt;MunEWA.aspx&lt;/em&gt;:&lt;/p&gt; &lt;div class="wlWriterSmartContent" id="scid:6960CE03-38FC-44df-87D4-FA4540212B06:99e08fef-e869-4d4f-afb0-fd816a07ec62" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;img src="http://blogs.msdn.com/photos/jannemattila/images/5929362/original.aspx" alt="" style="width:634px; height:375px;" /&gt;&lt;/div&gt; &lt;p&gt;(Note: Anyone who understands Finnish may laugh at my translations since I translated them smile in my face :-)&lt;/p&gt; &lt;p&gt;UI is pretty easy and straight forward: 1 dropdown to select product (=this is used as filter criteria in DB request) and 2 export buttons (Excel and CSV). If user would press &lt;em&gt;Export Excel &lt;/em&gt;output would be something like this:&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;div class="wlWriterSmartContent" id="scid:6960CE03-38FC-44df-87D4-FA4540212B06:39392043-6453-4fd4-a108-f154c1b4d53c" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;img src="http://blogs.msdn.com/photos/jannemattila/images/5929543/original.aspx" alt="" style="width:331px; height:556px;" /&gt;&lt;/div&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;And if user would press &lt;em&gt;Vie Exceliin&lt;/em&gt; output would be something like this:&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;div class="wlWriterSmartContent" id="scid:6960CE03-38FC-44df-87D4-FA4540212B06:776c3d78-7dba-4702-88e2-a0a11b6a0fd9" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;img src="http://blogs.msdn.com/photos/jannemattila/images/5929558/original.aspx" alt="" style="width:389px; height:540px;" /&gt;&lt;/div&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;Both of those export files are &lt;em&gt;Snapshots&lt;/em&gt; (=they don't contain formulas just data).&lt;/p&gt; &lt;p&gt;If user would use &lt;em&gt;Vie CSV&lt;/em&gt; -button (=Export to CSV) it would look something like this:&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;div class="wlWriterSmartContent" id="scid:6960CE03-38FC-44df-87D4-FA4540212B06:694d5e5d-4b49-46a4-b851-792c37b72e00" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;img src="http://blogs.msdn.com/photos/jannemattila/images/5930699/original.aspx" alt="" style="width:349px; height:540px;" /&gt;&lt;/div&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;(Note: You can see [again!] empty row 5... but I'll explain reason for that soon)&lt;/p&gt; &lt;p&gt;Now I think we're ready to start reading some code. Just to remind you that I have put all the functionality into this one .cs file but &lt;u&gt;in real life you don't do that&lt;/u&gt;! You refactor this kind of approach into several classes so that it is more maintainable. &lt;u&gt;My "one file approach" is for demonstration purposes only&lt;/u&gt;. Also improving error handling is out of scope of this demo. Access rights is also something that needs to be solved since that process needs to write files to file system. Of course that can be solved with &lt;em&gt;impersonation&lt;/em&gt; but anyway that needs to be taken into account. But finally here's the code:&lt;/p&gt; &lt;table cellspacing="10"&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td valign="top" align="right"&gt;&lt;pre&gt;&lt;font color="gray"&gt;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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
&lt;/font&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td valign="top"&gt;&lt;pre&gt;&lt;font color="blue"&gt;using&lt;/font&gt; System;
&lt;font color="blue"&gt;using&lt;/font&gt; System.Runtime.InteropServices;
&lt;font color="blue"&gt;using&lt;/font&gt; System.Web.UI;
&lt;font color="blue"&gt;using&lt;/font&gt; System.Web.UI.WebControls.WebParts;
&lt;font color="blue"&gt;using&lt;/font&gt; System.Xml.Serialization;
&lt;font color="blue"&gt;using&lt;/font&gt; Microsoft.SharePoint;
&lt;font color="blue"&gt;using&lt;/font&gt; Microsoft.Office.Excel.WebUI;
&lt;font color="blue"&gt;using&lt;/font&gt; System.IO;
&lt;font color="blue"&gt;using&lt;/font&gt; System.Threading;
&lt;font color="blue"&gt;using&lt;/font&gt; Microsoft.Office.Excel.Server.WebServices;
&lt;font color="blue"&gt;using&lt;/font&gt; System.Web.UI.WebControls;
&lt;font color="blue"&gt;using&lt;/font&gt; System.Web;
&lt;font color="blue"&gt;using&lt;/font&gt; System.Resources;
&lt;font color="blue"&gt;using&lt;/font&gt; System.Data;
&lt;font color="blue"&gt;using&lt;/font&gt; System.Data.SqlClient;
&lt;font color="blue"&gt;using&lt;/font&gt; System.Text;

&lt;font color="blue"&gt;namespace&lt;/font&gt; MyEWA
{
  [&lt;font color="#409090"&gt;Guid&lt;/font&gt;(&lt;font color="#aa2000"&gt;"97db47dc-7f23-4975-b246-26c237e74243"&lt;/font&gt;)]
  &lt;font color="blue"&gt;public&lt;/font&gt; &lt;font color="blue"&gt;class&lt;/font&gt; &lt;font color="#008080"&gt;MyEWA&lt;/font&gt; : System.Web.UI.WebControls.WebParts.&lt;font color="#008080"&gt;WebPart&lt;/font&gt;
  {
    &lt;font color="#008080"&gt;ExcelWebRenderer&lt;/font&gt; ewa;
    &lt;font color="#008080"&gt;DropDownList&lt;/font&gt; productsList;
    &lt;font color="#008080"&gt;Button&lt;/font&gt; exportSnapshot;
    &lt;font color="#008080"&gt;Button&lt;/font&gt; exportSnapshotCSV;
    &lt;font color="blue"&gt;string&lt;/font&gt; xlFileWithoutPath;
    &lt;font color="blue"&gt;string&lt;/font&gt; xlFile;
    &lt;font color="blue"&gt;string&lt;/font&gt; xlPath;
    &lt;font color="blue"&gt;string&lt;/font&gt; xlStorageDirectory;
    &lt;font color="blue"&gt;string&lt;/font&gt; xlTemplateFile;
    &lt;font color="blue"&gt;string&lt;/font&gt; culture;

    &lt;font color="blue"&gt;public&lt;/font&gt; MyEWA()
    {
      &lt;font color="blue"&gt;this&lt;/font&gt;.ExportMode = &lt;font color="#008080"&gt;WebPartExportMode&lt;/font&gt;.All;
    }

    &lt;font color="blue"&gt;private&lt;/font&gt; &lt;font color="blue"&gt;string&lt;/font&gt; ConnectionString
    {
      &lt;font color="#0000ff"&gt;get&lt;/font&gt;
      {
        &lt;font color="green"&gt;// ERROR: don't ever store connection string in your class!
&lt;/font&gt;        &lt;font color="blue"&gt;return&lt;/font&gt; &lt;font color="#aa2000"&gt;"..."&lt;/font&gt;;
      }
    }

    &lt;font color="green"&gt;// TODO: refactor this into separate class!
&lt;/font&gt;    &lt;font color="blue"&gt;private&lt;/font&gt; &lt;font color="#008080"&gt;DataTable&lt;/font&gt; GetExcelData(&lt;font color="blue"&gt;string&lt;/font&gt; product, &lt;font color="blue"&gt;string&lt;/font&gt; culture)
    {
      &lt;font color="blue"&gt;using&lt;/font&gt; (&lt;font color="#008080"&gt;SqlConnection&lt;/font&gt; conn = &lt;font color="blue"&gt;new&lt;/font&gt; &lt;font color="#008080"&gt;SqlConnection&lt;/font&gt;(&lt;font color="blue"&gt;this&lt;/font&gt;.ConnectionString))
      {
        &lt;font color="green"&gt;// If you have translations inside your database you can pass on the culture to the db:
&lt;/font&gt;        &lt;font color="#008080"&gt;SqlCommand&lt;/font&gt; cmd = &lt;font color="blue"&gt;new&lt;/font&gt; &lt;font color="#008080"&gt;SqlCommand&lt;/font&gt;(
          &lt;font color="#aa2000"&gt;"SELECT Production.vProductAndDescription.ProductModel, "&lt;/font&gt; +
          &lt;font color="#aa2000"&gt;"Production.vProductAndDescription.Description AS Product, "&lt;/font&gt; +
          &lt;font color="#aa2000"&gt;"Production.Product.ListPrice AS Price "&lt;/font&gt; +
          &lt;font color="#aa2000"&gt;"FROM Production.vProductAndDescription INNER JOIN "&lt;/font&gt; +
          &lt;font color="#aa2000"&gt;"Production.Product ON "&lt;/font&gt; +
          &lt;font color="#aa2000"&gt;"Production.vProductAndDescription.ProductID = Production.Product.ProductID AND "&lt;/font&gt; +
          &lt;font color="#aa2000"&gt;"Production.vProductAndDescription.ProductModel LIKE @Product+'%' AND "&lt;/font&gt; +
          &lt;font color="#aa2000"&gt;"Production.vProductAndDescription.CultureID LIKE @Culture+'%'"&lt;/font&gt;, conn);

        cmd.Parameters.AddWithValue(&lt;font color="#aa2000"&gt;"@Product"&lt;/font&gt;, product);
        cmd.Parameters.AddWithValue(&lt;font color="#aa2000"&gt;"@Culture"&lt;/font&gt;, culture.Substring(0,2));

        &lt;font color="#008080"&gt;SqlDataAdapter&lt;/font&gt; adapter = &lt;font color="blue"&gt;new&lt;/font&gt; &lt;font color="#008080"&gt;SqlDataAdapter&lt;/font&gt;(cmd);
        &lt;font color="#008080"&gt;DataSet&lt;/font&gt; ds = &lt;font color="blue"&gt;new&lt;/font&gt; &lt;font color="#008080"&gt;DataSet&lt;/font&gt;();
        adapter.Fill(ds);

        &lt;font color="blue"&gt;return&lt;/font&gt; ds.Tables[0];
      }
    }

    &lt;font color="blue"&gt;protected&lt;/font&gt; &lt;font color="blue"&gt;override&lt;/font&gt; &lt;font color="blue"&gt;void&lt;/font&gt; CreateChildControls()
    {
      &lt;font color="green"&gt;// Get default locale from current site:
&lt;/font&gt;      &lt;font color="green"&gt;// (Note: this can be changed from site settings)
&lt;/font&gt;      culture = SPContext.Current.Web.Locale.ToString();
      &lt;font color="blue"&gt;if&lt;/font&gt; (&lt;font color="blue"&gt;string&lt;/font&gt;.IsNullOrEmpty(&lt;font color="blue"&gt;this&lt;/font&gt;.Page.Request[&lt;font color="#aa2000"&gt;&lt;font color="#aa2000"&gt;"Language"&lt;/font&gt;&lt;/font&gt;]) == &lt;font color="blue"&gt;false&lt;/font&gt;)
      {
        &lt;font color="green"&gt;// I'll give way to change the language on the fly:
&lt;/font&gt;        culture = &lt;font color="blue"&gt;this&lt;/font&gt;.Page.Request[&lt;font color="#aa2000"&gt;&lt;font color="#aa2000"&gt;"Language"&lt;/font&gt;&lt;/font&gt;];

        &lt;font color="#008080"&gt;Thread&lt;/font&gt;.CurrentThread.CurrentCulture = &lt;font color="blue"&gt;new&lt;/font&gt; System.Globalization.&lt;font color="#008080"&gt;CultureInfo&lt;/font&gt;(culture);
        &lt;font color="#008080"&gt;Thread&lt;/font&gt;.CurrentThread.CurrentUICulture = &lt;font color="blue"&gt;new&lt;/font&gt; System.Globalization.&lt;font color="#008080"&gt;CultureInfo&lt;/font&gt;(culture); 
      }

      Controls.Clear();
      &lt;font color="blue"&gt;base&lt;/font&gt;.CreateChildControls();
      &lt;font color="blue"&gt;this&lt;/font&gt;.ChildControlsCreated = &lt;font color="blue"&gt;true&lt;/font&gt;;

      &lt;font color="#008080"&gt;Label&lt;/font&gt; productLabel = &lt;font color="blue"&gt;new&lt;/font&gt; &lt;font color="#008080"&gt;Label&lt;/font&gt;();
      productLabel.Text = &lt;font color="#008080"&gt;MyEWAResources&lt;/font&gt;.ProductList_Select;
      &lt;font color="blue"&gt;this&lt;/font&gt;.Controls.Add(productLabel);

      productsList = &lt;font color="blue"&gt;new&lt;/font&gt; &lt;font color="#008080"&gt;DropDownList&lt;/font&gt;();
      productsList.ID = &lt;font color="#aa2000"&gt;"productsList"&lt;/font&gt;;
      &lt;font color="green"&gt;// TODO: get your product filter list using SQL statements
&lt;/font&gt;      &lt;font color="green"&gt;// and remember to store that in cache =&amp;gt; performance.
&lt;/font&gt;      &lt;font color="green"&gt;// Something like this:
&lt;/font&gt;      &lt;font color="green"&gt;// this.Page.Cache.Add("ProductList", ...);
&lt;/font&gt;      &lt;font color="green"&gt;// And of course you can use SqlCacheDependency if you want.
&lt;/font&gt;
      &lt;font color="green"&gt;// I'll just fill in static filters (I'm lazy!):
&lt;/font&gt;      productsList.Items.Add(&lt;font color="blue"&gt;new&lt;/font&gt; ListItem(&lt;font color="#008080"&gt;MyEWAResources&lt;/font&gt;.ProductList_Item1, &lt;font color="#aa2000"&gt;"Mountain"&lt;/font&gt;));
      productsList.Items.Add(&lt;font color="blue"&gt;new&lt;/font&gt; ListItem(&lt;font color="#008080"&gt;MyEWAResources&lt;/font&gt;.ProductList_Item2, &lt;font color="#aa2000"&gt;"Road"&lt;/font&gt;));
      productsList.Items.Add(&lt;font color="blue"&gt;new&lt;/font&gt; ListItem(&lt;font color="#008080"&gt;MyEWAResources&lt;/font&gt;.ProductList_Item3, &lt;font color="#aa2000"&gt;"HL"&lt;/font&gt;));
      productsList.AutoPostBack = &lt;font color="blue"&gt;true&lt;/font&gt;;
      &lt;font color="blue"&gt;this&lt;/font&gt;.Controls.Add(productsList);

      &lt;font color="green"&gt;// Create some buttons:
&lt;/font&gt;      exportSnapshot = &lt;font color="blue"&gt;new&lt;/font&gt; &lt;font color="#008080"&gt;Button&lt;/font&gt;();
      exportSnapshot.Text = &lt;font color="#008080"&gt;MyEWAResources&lt;/font&gt;.ExportSnapshot;
      &lt;font color="blue"&gt;this&lt;/font&gt;.Controls.Add(exportSnapshot);

      exportSnapshotCSV = &lt;font color="blue"&gt;new&lt;/font&gt; &lt;font color="#008080"&gt;Button&lt;/font&gt;();
      exportSnapshotCSV.Text = &lt;font color="#008080"&gt;MyEWAResources&lt;/font&gt;.ExportSnapshotCSV;
      &lt;font color="blue"&gt;this&lt;/font&gt;.Controls.Add(exportSnapshotCSV);

      ewa = &lt;font color="blue"&gt;new&lt;/font&gt; &lt;font color="#008080"&gt;ExcelWebRenderer&lt;/font&gt;();
      &lt;font color="blue"&gt;this&lt;/font&gt;.Controls.Add(ewa);
    }

    &lt;font color="blue"&gt;protected&lt;/font&gt; &lt;font color="blue"&gt;override&lt;/font&gt; &lt;font color="blue"&gt;void&lt;/font&gt; OnLoad(&lt;font color="#409090"&gt;EventArgs&lt;/font&gt; e)
    {
      &lt;font color="blue"&gt;this&lt;/font&gt;.EnsureChildControls();
      &lt;font color="blue"&gt;base&lt;/font&gt;.OnLoad(e);

      &lt;font color="green"&gt;// Get values from UI:
&lt;/font&gt;      &lt;font color="blue"&gt;string&lt;/font&gt; productFilter = productsList.SelectedValue;

      &lt;font color="green"&gt;// TODO: get these values from web part properties!!!
&lt;/font&gt;      &lt;font color="green"&gt;// This is the UNC path of the Excel files:
&lt;/font&gt;      xlPath = &lt;font color="#aa2000"&gt;"//demo1/ExcelServices/xlsx";
&lt;/font&gt;      &lt;font color="green"&gt;// This is folder where static instances will be created (under previous folder)
&lt;/font&gt;      xlStorageDirectory = &lt;font color="#aa2000"&gt;"Storage/"&lt;/font&gt;;
      &lt;font color="green"&gt;// This name of the static Excel file:
&lt;/font&gt;      xlFileWithoutPath = &lt;font color="blue"&gt;string&lt;/font&gt;.Format(&lt;font color="#aa2000"&gt;"MyEWA-{0}-{1}.xlsx"&lt;/font&gt;, culture, productFilter);
      &lt;font color="green"&gt;// This name of the template Excel file
&lt;/font&gt;      &lt;font color="green"&gt;// NOTE: You should store this inside SharePoint!!!
&lt;/font&gt;      xlTemplateFile = xlPath + &lt;font color="#aa2000"&gt;"MyEWA.xlsx"&lt;/font&gt;;
      xlFile = xlPath + xlStorageDirectory + xlFileWithoutPath;

      &lt;font color="green"&gt;// Let's add Export calls to the client side of the buttons:
&lt;/font&gt;      exportSnapshot.OnClientClick = &lt;font color="blue"&gt;this&lt;/font&gt;.BuildExportScript(&lt;font color="#aa2000"&gt;&lt;font color="#aa2000"&gt;"xlsx"&lt;/font&gt;&lt;/font&gt;, xlFileWithoutPath);
      exportSnapshotCSV.OnClientClick = &lt;font color="blue"&gt;this&lt;/font&gt;.BuildExportScript(&lt;font color="#aa2000"&gt;&lt;font color="#aa2000"&gt;"csv"&lt;/font&gt;&lt;/font&gt;, xlFileWithoutPath);

      &lt;font color="green"&gt;// Do we need to export file? (new .aspx page for this would be good idea!)
&lt;/font&gt;      &lt;font color="blue"&gt;if&lt;/font&gt; (&lt;font color="blue"&gt;string&lt;/font&gt;.IsNullOrEmpty(&lt;font color="blue"&gt;this&lt;/font&gt;.Page.Request[&lt;font color="#aa2000"&gt;&lt;font color="#aa2000"&gt;"ExportFormat"&lt;/font&gt;&lt;/font&gt;]) == &lt;font color="blue"&gt;false&lt;/font&gt; &amp;amp;&amp;amp;
          &lt;font color="blue"&gt;string&lt;/font&gt;.IsNullOrEmpty(&lt;font color="blue"&gt;this&lt;/font&gt;.Page.Request[&lt;font color="#aa2000"&gt;&lt;font color="#aa2000"&gt;"File"&lt;/font&gt;&lt;/font&gt;]) == &lt;font color="blue"&gt;false&lt;/font&gt;)
      {
        &lt;font color="green"&gt;// Yes we need to export file
&lt;/font&gt;
        &lt;font color="green"&gt;// TODO: add sanity checks for the filename
&lt;/font&gt;        xlFile = xlPath + xlStorageDirectory + &lt;font color="blue"&gt;this&lt;/font&gt;.Page.Request[&lt;font color="#aa2000"&gt;&lt;font color="#aa2000"&gt;"File"&lt;/font&gt;&lt;/font&gt;].ToString();
        &lt;font color="blue"&gt;string&lt;/font&gt; format = &lt;font color="blue"&gt;this&lt;/font&gt;.Page.Request[&lt;font color="#aa2000"&gt;&lt;font color="#aa2000"&gt;"ExportFormat"&lt;/font&gt;&lt;/font&gt;].ToString();
        &lt;font color="blue"&gt;switch&lt;/font&gt; (format)
        {
          &lt;font color="blue"&gt;case&lt;/font&gt; &lt;font color="#aa2000"&gt;&lt;font color="#aa2000"&gt;"csv"&lt;/font&gt;&lt;/font&gt;:
            ExportSnapshotAsCSV();
            &lt;font color="blue"&gt;break&lt;/font&gt;;
          &lt;font color="blue"&gt;case&lt;/font&gt; &lt;font color="#aa2000"&gt;&lt;font color="#aa2000"&gt;"xlsx"&lt;/font&gt;&lt;/font&gt;:
            ExportSnapshotAsExcel();
            &lt;font color="blue"&gt;break&lt;/font&gt;;
          &lt;font color="#0000ff"&gt;default&lt;/font&gt;:
            &lt;font color="blue"&gt;throw&lt;/font&gt; &lt;font color="blue"&gt;new&lt;/font&gt; &lt;font color="#409090"&gt;Exception&lt;/font&gt;(
              &lt;font color="blue"&gt;string&lt;/font&gt;.Format(&lt;font color="#aa2000"&gt;"Export format '{0}' not supported!"&lt;/font&gt;, format));
        }
      }

      &lt;font color="green"&gt;// Does the cache file already exists?
&lt;/font&gt;      &lt;font color="#0000ff"&gt;bool&lt;/font&gt; useCachedXlFile = &lt;font color="#008080"&gt;File&lt;/font&gt;.Exists(xlFile);
      &lt;font color="blue"&gt;if&lt;/font&gt; (useCachedXlFile == &lt;font color="blue"&gt;true&lt;/font&gt;)
      {
        &lt;font color="green"&gt;// Cache file exists but let's compare timestamps:
&lt;/font&gt;        &lt;font color="#008080"&gt;FileInfo&lt;/font&gt; src = &lt;font color="blue"&gt;new&lt;/font&gt; &lt;font color="#008080"&gt;FileInfo&lt;/font&gt;(xlTemplateFile);
        &lt;font color="#008080"&gt;FileInfo&lt;/font&gt; dst = &lt;font color="blue"&gt;new&lt;/font&gt; &lt;font color="#008080"&gt;FileInfo&lt;/font&gt;(xlFile);
        &lt;font color="blue"&gt;if&lt;/font&gt; (src.LastWriteTimeUtc &amp;gt; dst.LastWriteTimeUtc)
        {
          &lt;font color="green"&gt;// Template file is newer than cache file!
&lt;/font&gt;          useCachedXlFile = &lt;font color="blue"&gt;false&lt;/font&gt;;
        }
      }

      &lt;font color="blue"&gt;if&lt;/font&gt; (useCachedXlFile == &lt;font color="blue"&gt;true&lt;/font&gt;)
      {
        &lt;font color="green"&gt;// TODO: add your own custom logic to check that cache is still valid
&lt;/font&gt;        &lt;font color="green"&gt;// I.e. check site property bag about 'UpdateExcels' timestamp
&lt;/font&gt;      }

      &lt;font color="blue"&gt;if&lt;/font&gt; (useCachedXlFile == &lt;font color="blue"&gt;false&lt;/font&gt;)
      {
        &lt;font color="green"&gt;// We need to create the cache file!
&lt;/font&gt;
        &lt;font color="green"&gt;// Let's get data to the Excel:
&lt;/font&gt;        &lt;font color="#008080"&gt;DataTable&lt;/font&gt; excelData = &lt;font color="blue"&gt;this&lt;/font&gt;.GetExcelData(productFilter, culture);
        &lt;font color="green"&gt;// In my example 'Description' field is actually already translated in the db
&lt;/font&gt;        &lt;font color="green"&gt;// so we need to translated only the 'ProductModel' in our data
&lt;/font&gt;        &lt;font color="green"&gt;// (this is here just to demonstrate that text can be translated in many 
&lt;/font&gt;        &lt;font color="green"&gt;// different layers: Excel, Code, DB etc.)
&lt;/font&gt;        &lt;font color="blue"&gt;if&lt;/font&gt; (culture.StartsWith(&lt;font color="#aa2000"&gt;"en"&lt;/font&gt;, &lt;font color="#008080"&gt;StringComparison&lt;/font&gt;.OrdinalIgnoreCase) == &lt;font color="blue"&gt;false&lt;/font&gt;)
        {
          &lt;font color="green"&gt;// This culture isn't the "original" database culture 
&lt;/font&gt;          &lt;font color="green"&gt;// so we need to translate "ProductModel" field
&lt;/font&gt;
          &lt;font color="green"&gt;// TODO: implement real translation 
&lt;/font&gt;          &lt;font color="blue"&gt;foreach&lt;/font&gt; (&lt;font color="#008080"&gt;DataRow&lt;/font&gt; row in excelData.Rows)
          {
            row[&lt;font color="#aa2000"&gt;&lt;font color="#aa2000"&gt;&lt;font color="#aa2000"&gt;"ProductModel"&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;] = &lt;font color="#aa2000"&gt;"Suomeksi - "&lt;/font&gt; + row[&lt;font color="#aa2000"&gt;&lt;font color="#aa2000"&gt;&lt;font color="#aa2000"&gt;"ProductModel"&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;];
            row.AcceptChanges();
          }
          excelData.AcceptChanges();
        }

        &lt;font color="blue"&gt;using&lt;/font&gt; (&lt;font color="#008080"&gt;ExcelService&lt;/font&gt; es = &lt;font color="blue"&gt;new&lt;/font&gt; &lt;font color="#008080"&gt;ExcelService&lt;/font&gt;())
        {
          &lt;font color="#008080"&gt;Status&lt;/font&gt;[] status;
          &lt;font color="blue"&gt;string&lt;/font&gt; sessionId = es.OpenWorkbook(xlTemplateFile, culture, culture, &lt;font color="blue"&gt;out&lt;/font&gt; status);
          &lt;font color="green"&gt;// Set culture to the parameters:
&lt;/font&gt;          es.SetCellA1(sessionId, &lt;font color="#aa2000"&gt;"Parameters"&lt;/font&gt;, &lt;font color="#aa2000"&gt;"Culture"&lt;/font&gt;, culture, &lt;font color="blue"&gt;out&lt;/font&gt; status);

          &lt;font color="green"&gt;// TODO: get your fancy data with current information:
&lt;/font&gt;          &lt;font color="blue"&gt;object&lt;/font&gt;[] excelDataArray = &lt;font color="blue"&gt;new&lt;/font&gt; &lt;font color="blue"&gt;object&lt;/font&gt;[excelData.Rows.Count + 1];
          &lt;font color="blue"&gt;object&lt;/font&gt;[] excelRowArray = &lt;font color="blue"&gt;new&lt;/font&gt; &lt;font color="blue"&gt;object&lt;/font&gt;[excelData.Columns.Count];

          &lt;font color="green"&gt;// You might think that you could change the columns of your data with following code:
&lt;/font&gt;          &lt;font color="#008000"&gt;// for (int i = 0; i &amp;lt; excelData.Columns.Count; i++)
          // {
          //   // Get correct labels for the texts:
          //   excelRowArray[i] = MyEWAResources.ResourceManager.GetString(
          //     "Column_" + excelData.Columns[i].ColumnName);
          // }
&lt;/font&gt;          &lt;font color="green"&gt;// BUT BUT BUT... You cannot change columns since Pivottable won't work after that :-(
&lt;/font&gt;
          excelDataArray[0] = excelRowArray;

          &lt;font color="green"&gt;// Fill the data with retrieved values:
&lt;/font&gt;          &lt;font color="blue"&gt;for&lt;/font&gt; (&lt;font color="blue"&gt;int&lt;/font&gt; i = 0; i &amp;lt; excelData.Rows.Count; i++)
          {
            excelRowArray = &lt;font color="blue"&gt;new&lt;/font&gt; &lt;font color="blue"&gt;object&lt;/font&gt;[excelData.Columns.Count];
            &lt;font color="blue"&gt;for&lt;/font&gt; (&lt;font color="blue"&gt;int&lt;/font&gt; j = 0; j &amp;lt; excelData.Columns.Count; j++)
            {
              excelRowArray[j] = excelData.Rows[i][excelData.Columns[j]];
            }
            excelDataArray[i + 1] = excelRowArray;
          }
          
          &lt;font color="#008080"&gt;RangeCoordinates&lt;/font&gt; range = &lt;font color="blue"&gt;new&lt;/font&gt; &lt;font color="#008080"&gt;RangeCoordinates&lt;/font&gt;();
          range.Column = 0;
          range.Row = 1;
          range.Width = excelData.Columns.Count;
          range.Height = excelData.Rows.Count + 1;

          &lt;font color="green"&gt;// Store data into Excel:
&lt;/font&gt;          es.SetRange(sessionId, &lt;font color="#aa2000"&gt;"Data"&lt;/font&gt;, range, excelDataArray, &lt;font color="blue"&gt;out&lt;/font&gt; status);

          &lt;font color="green"&gt;// You might think that you could change the Pivottable captions on the fly:
&lt;/font&gt;          &lt;font color="green"&gt;// es.SetCellA1(sessionId, "Display", "A5", "My new pivot caption", out status);
&lt;/font&gt;          &lt;font color="green"&gt;// BUT BUT BUT.. It doesn't work (=nothing happens) :-(
&lt;/font&gt;
          &lt;font color="green"&gt;// Let's refresh our datasources (=update pivottable):
&lt;/font&gt;          es.Refresh(sessionId, &lt;font color="blue"&gt;null&lt;/font&gt;, &lt;font color="blue"&gt;out&lt;/font&gt; status);

          &lt;font color="green"&gt;// Following 'block' of code can be used if you want to have
&lt;/font&gt;          &lt;font color="green"&gt;// separate sheet in your Excel file for translations:
&lt;/font&gt;          &lt;font color="green"&gt;//
&lt;/font&gt;          &lt;font color="green"&gt;//bool doneTranslations = false;
&lt;/font&gt;          &lt;font color="green"&gt;//range = new RangeCoordinates();
&lt;/font&gt;          &lt;font color="green"&gt;//range.Column = 0;
&lt;/font&gt;          &lt;font color="green"&gt;//range.Row = 1;
&lt;/font&gt;          &lt;font color="green"&gt;//range.Width = 2;
&lt;/font&gt;          &lt;font color="green"&gt;//range.Height = 10;
&lt;/font&gt;          &lt;font color="green"&gt;//while (doneTranslations == false)
&lt;/font&gt;          &lt;font color="green"&gt;//{
&lt;/font&gt;          &lt;font color="green"&gt;//  // So we get all the data from Translations-sheet and then we
&lt;/font&gt;          &lt;font color="green"&gt;//  // copy the text over to the locations defined in Excel:
&lt;/font&gt;          &lt;font color="green"&gt;//  object[] rowData = es.GetRange(sessionId, 
&lt;/font&gt;          &lt;font color="green"&gt;//    "Translations", range, false, out status);
&lt;/font&gt;          &lt;font color="green"&gt;//  for (int i = 0; i &amp;lt; range.Height; i++)
&lt;/font&gt;          &lt;font color="green"&gt;//  {
&lt;/font&gt;          &lt;font color="green"&gt;//    if (rowData is object[])
&lt;/font&gt;          &lt;font color="green"&gt;//    {
&lt;/font&gt;          &lt;font color="green"&gt;//      object[] columnData = rowData[i] as object[];
&lt;/font&gt;          &lt;font color="green"&gt;//      if (columnData[0] == null)
&lt;/font&gt;          &lt;font color="green"&gt;//      {
&lt;/font&gt;          &lt;font color="green"&gt;//        // No more translations
&lt;/font&gt;          &lt;font color="green"&gt;//        doneTranslations = true;
&lt;/font&gt;          &lt;font color="green"&gt;//        break;
&lt;/font&gt;          &lt;font color="green"&gt;//      }
&lt;/font&gt;          &lt;font color="green"&gt;//      string[] translationRange = Convert.ToString(columnData[0]).Split('!');
&lt;/font&gt;          &lt;font color="green"&gt;//      es.SetCellA1(sessionId, translationRange[0], translationRange[1],
&lt;/font&gt;          &lt;font color="green"&gt;//        Convert.ToString(columnData[1]), out status);
&lt;/font&gt;          &lt;font color="green"&gt;//    }
&lt;/font&gt;          &lt;font color="green"&gt;//  }
&lt;/font&gt;          &lt;font color="green"&gt;//  range.Row += range.Height;
&lt;/font&gt;          &lt;font color="green"&gt;//}
&lt;/font&gt;          &lt;br&gt;          &lt;font color="#008000"&gt;// Do we calculations that we need to refresh?&lt;/font&gt;&lt;br&gt;          es.CalculateWorkbook(sessionId, &lt;font color="#008080"&gt;CalculateType&lt;/font&gt;.CalculateFull, &lt;font color="blue"&gt;out&lt;/font&gt; status);
          &lt;font color="#0000ff"&gt;byte&lt;/font&gt;[] wb = es.GetWorkbook(sessionId, &lt;font color="#008080"&gt;WorkbookType&lt;/font&gt;.FullWorkbook, &lt;font color="blue"&gt;out&lt;/font&gt; status);
          es.CloseWorkbook(sessionId, &lt;font color="blue"&gt;out&lt;/font&gt; status);

          &lt;font color="green"&gt;// Let's write our cache file to the disk:
&lt;/font&gt;          &lt;font color="green"&gt;// (you need to have write rights for that location!)
&lt;/font&gt;          &lt;font color="#008080"&gt;File&lt;/font&gt;.WriteAllBytes(xlFile, wb);
        }
      }

      &lt;font color="green"&gt;// TODO: set all necessary parameters to EWA:
&lt;/font&gt;      ewa.ShowWorkbookParameters = &lt;font color="blue"&gt;false&lt;/font&gt;;
      ewa.WorkbookUri = &lt;font color="#008080"&gt;Uri&lt;/font&gt;.UriSchemeFile + &lt;font color="#008080"&gt;Uri&lt;/font&gt;.SchemeDelimiter + xlFile;
      ewa.ToolbarStyle = &lt;font color="#008080"&gt;ToolbarVisibilityStyle&lt;/font&gt;.None;
      ewa.ChromeType = &lt;font color="#008080"&gt;PartChromeType&lt;/font&gt;.None;

      &lt;font color="green"&gt;// TODO: you can also get settings from various places:
&lt;/font&gt;      &lt;font color="blue"&gt;if&lt;/font&gt; (&lt;font color="blue"&gt;string&lt;/font&gt;.IsNullOrEmpty(&lt;font color="blue"&gt;this&lt;/font&gt;.Page.Request[&lt;font color="#aa2000"&gt;&lt;font color="#aa2000"&gt;"NamedItem"&lt;/font&gt;&lt;/font&gt;]) == &lt;font color="blue"&gt;false&lt;/font&gt;)
      {
        ewa.VisibleItem = &lt;font color="blue"&gt;this&lt;/font&gt;.Page.Request[&lt;font color="#aa2000"&gt;&lt;font color="#aa2000"&gt;"NamedItem"&lt;/font&gt;&lt;/font&gt;].ToString();
      }
      &lt;font color="blue"&gt;if&lt;/font&gt; (&lt;font color="blue"&gt;string&lt;/font&gt;.IsNullOrEmpty(&lt;font color="blue"&gt;this&lt;/font&gt;.Page.Request[&lt;font color="#aa2000"&gt;&lt;font color="#aa2000"&gt;"Rows"&lt;/font&gt;&lt;/font&gt;]) == &lt;font color="blue"&gt;false&lt;/font&gt;)
      {
        ewa.RowsToDisplay = &lt;font color="#008080"&gt;Convert&lt;/font&gt;.ToInt32(&lt;font color="blue"&gt;this&lt;/font&gt;.Page.Request[&lt;font color="#aa2000"&gt;&lt;font color="#aa2000"&gt;"Rows"&lt;/font&gt;&lt;/font&gt;]);
      }
      &lt;font color="blue"&gt;if&lt;/font&gt; (&lt;font color="blue"&gt;string&lt;/font&gt;.IsNullOrEmpty(&lt;font color="blue"&gt;this&lt;/font&gt;.Page.Request[&lt;font color="#aa2000"&gt;&lt;font color="#aa2000"&gt;"Columns"&lt;/font&gt;&lt;/font&gt;]) == &lt;font color="blue"&gt;false&lt;/font&gt;)
      {
        ewa.ColumnsToDisplay = &lt;font color="#008080"&gt;Convert&lt;/font&gt;.ToInt32(&lt;font color="blue"&gt;this&lt;/font&gt;.Page.Request[&lt;font color="#aa2000"&gt;&lt;font color="#aa2000"&gt;"Columns"&lt;/font&gt;&lt;/font&gt;]);
      }
    }

    &lt;font color="blue"&gt;private&lt;/font&gt; &lt;font color="blue"&gt;string&lt;/font&gt; GetSnapshotFile()
    {
      &lt;font color="#0000ff"&gt;byte&lt;/font&gt;[] wb;
      &lt;font color="blue"&gt;string&lt;/font&gt; snapshotCacheFile = xlFile + &lt;font color="#aa2000"&gt;".snapshot.xlsx"&lt;/font&gt;;
      &lt;font color="blue"&gt;if&lt;/font&gt; (&lt;font color="#008080"&gt;File&lt;/font&gt;.Exists(snapshotCacheFile) == &lt;font color="blue"&gt;false&lt;/font&gt;)
      {
        &lt;font color="green"&gt;&lt;font color="green"&gt;// No cache file yet.. so let's create it:
&lt;/font&gt;&lt;/font&gt;        &lt;font color="blue"&gt;using&lt;/font&gt; (&lt;font color="#008080"&gt;ExcelService&lt;/font&gt; es = &lt;font color="blue"&gt;new&lt;/font&gt; &lt;font color="#008080"&gt;ExcelService&lt;/font&gt;())
        {
          &lt;font color="#008080"&gt;Status&lt;/font&gt;[] status;
          &lt;font color="blue"&gt;string&lt;/font&gt; sessionId = es.OpenWorkbook(xlFile, culture, culture, &lt;font color="blue"&gt;out&lt;/font&gt; status);
          &lt;font color="green"&gt;// Note! If we take the 'normal' excel file then we return formulas as well
&lt;/font&gt;          &lt;font color="green"&gt;// =&amp;gt; we really want to use the snapshot file!
&lt;/font&gt;          wb = es.GetWorkbook(sessionId, &lt;font color="#008080"&gt;WorkbookType&lt;/font&gt;.PublishedItemsSnapshot, &lt;font color="blue"&gt;out&lt;/font&gt; status);
          es.CloseWorkbook(sessionId, &lt;font color="blue"&gt;out&lt;/font&gt; status);
        }

        &lt;font color="#008080"&gt;File&lt;/font&gt;.WriteAllBytes(snapshotCacheFile, wb);
      }

      &lt;font color="blue"&gt;return&lt;/font&gt; snapshotCacheFile;
    }

    &lt;font color="blue"&gt;private&lt;/font&gt; &lt;font color="blue"&gt;string&lt;/font&gt; BuildExportScript(&lt;font color="blue"&gt;string&lt;/font&gt; exportFormat, &lt;font color="blue"&gt;string&lt;/font&gt; file)
    {
      &lt;font color="blue"&gt;string&lt;/font&gt; url = &lt;font color="blue"&gt;this&lt;/font&gt;.Page.Request.Url.ToString();
      &lt;font color="blue"&gt;if&lt;/font&gt; (url.IndexOf(&lt;font color="#800000"&gt;'?'&lt;/font&gt;) == -1)
      {
        url += &lt;font color="#aa2000"&gt;"?"&lt;/font&gt;;
      }
      &lt;font color="blue"&gt;&lt;font color="blue"&gt;else&lt;/font&gt;&lt;/font&gt;
      {
        url += &lt;font color="#aa2000"&gt;"&amp;amp;"&lt;/font&gt;;
      }
      url += &lt;font color="#aa2000"&gt;"ExportFormat="&lt;/font&gt; + exportFormat + &lt;font color="#aa2000"&gt;"&amp;amp;File="&lt;/font&gt; + file;
      &lt;font color="blue"&gt;return&lt;/font&gt; &lt;font color="#aa2000"&gt;"window.frames['MyEWA'].location='"&lt;/font&gt; + url + &lt;font color="#aa2000"&gt;"'; return false;"&lt;/font&gt;;
    }

    &lt;font color="blue"&gt;private&lt;/font&gt; &lt;font color="blue"&gt;void&lt;/font&gt; ExportSnapshotAsExcel()
    {
      &lt;font color="#0000ff"&gt;byte&lt;/font&gt;[] fileData = &lt;font color="#008080"&gt;File&lt;/font&gt;.ReadAllBytes(&lt;font color="blue"&gt;this&lt;/font&gt;.GetSnapshotFile());
      &lt;font color="green"&gt;&lt;font color="green"&gt;// TODO: set meaningful name for the file (end user sees it File Download dialog)
&lt;/font&gt;&lt;/font&gt;      &lt;font color="blue"&gt;string&lt;/font&gt; filename = &lt;font color="#aa2000"&gt;"ExcelData.xlsx"&lt;/font&gt;;
      &lt;font color="blue"&gt;this&lt;/font&gt;.Page.Response.ClearHeaders();
      &lt;font color="blue"&gt;this&lt;/font&gt;.Page.Response.ClearContent();
      &lt;font color="blue"&gt;this&lt;/font&gt;.Page.Response.AppendHeader(&lt;font color="#aa2000"&gt;&lt;font color="#aa2000"&gt;"Content-Disposition"&lt;/font&gt;&lt;/font&gt;, 
        &lt;font color="#aa2000"&gt;&lt;font color="#aa2000"&gt;"attachment;filename="&lt;/font&gt;&lt;/font&gt; + filename);
      &lt;font color="blue"&gt;this&lt;/font&gt;.Page.Response.AddHeader(&lt;font color="#aa2000"&gt;&lt;font color="#aa2000"&gt;"LAST-MODIFIED"&lt;/font&gt;&lt;/font&gt;, DateTime.Now.ToString(&lt;font color="#aa2000"&gt;&lt;font color="#aa2000"&gt;"r"&lt;/font&gt;&lt;/font&gt;));
      &lt;font color="blue"&gt;this&lt;/font&gt;.Page.Response.ContentType = 
        &lt;font color="#aa2000"&gt;"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"&lt;/font&gt;;
      &lt;font color="blue"&gt;this&lt;/font&gt;.Page.Response.OutputStream.Write(fileData, 0, fileData.Length);
      &lt;font color="blue"&gt;this&lt;/font&gt;.Page.Response.OutputStream.Flush();
      &lt;font color="blue"&gt;this&lt;/font&gt;.Page.Response.End();
    }

    &lt;font color="blue"&gt;private&lt;/font&gt; &lt;font color="blue"&gt;string&lt;/font&gt; GetSnapshotFileCSV()
    {
      &lt;font color="#409090"&gt;StringBuilder&lt;/font&gt; sb = &lt;font color="blue"&gt;new&lt;/font&gt; &lt;font color="#409090"&gt;StringBuilder&lt;/font&gt;(2048);
      &lt;font color="blue"&gt;string&lt;/font&gt; snapshotCacheFile = xlFile + &lt;font color="#aa2000"&gt;".snapshot.csv"&lt;/font&gt;;
      &lt;font color="blue"&gt;if&lt;/font&gt; (&lt;font color="#008080"&gt;File&lt;/font&gt;.Exists(snapshotCacheFile) == &lt;font color="blue"&gt;false&lt;/font&gt;)
      {
        &lt;font color="green"&gt;&lt;font color="green"&gt;// No cache file yet.. so let's create it:
&lt;/font&gt;&lt;/font&gt;        &lt;font color="blue"&gt;using&lt;/font&gt; (&lt;font color="#008080"&gt;ExcelService&lt;/font&gt; es = &lt;font color="blue"&gt;new&lt;/font&gt; &lt;font color="#008080"&gt;ExcelService&lt;/font&gt;())
        {
          &lt;font color="#008080"&gt;Status&lt;/font&gt;[] status;
          &lt;font color="blue"&gt;string&lt;/font&gt; sessionId = es.OpenWorkbook
            (&lt;font color="blue"&gt;this&lt;/font&gt;.GetSnapshotFile(), culture, culture, &lt;font color="blue"&gt;out&lt;/font&gt; status);
          RangeCoordinates range = &lt;font color="blue"&gt;new&lt;/font&gt; RangeCoordinates();
          range.Column = 0;
          range.Row = 0;
          &lt;font color="green"&gt;// TODO: get real range according to the data (not fixed :-)
&lt;/font&gt;          &lt;font color="green"&gt;// You could store the value when you fill the Excel with data...
&lt;/font&gt;          range.Width = 5;
          range.Height = 300;

          &lt;font color="blue"&gt;object&lt;/font&gt;[] data = es.GetRange(sessionId, &lt;font color="#aa2000"&gt;&lt;font color="#aa2000"&gt;"Display"&lt;/font&gt;&lt;/font&gt;, range, &lt;font color="blue"&gt;false&lt;/font&gt;, &lt;font color="blue"&gt;out&lt;/font&gt; status);
          &lt;font color="blue"&gt;foreach&lt;/font&gt; (&lt;font color="blue"&gt;object&lt;/font&gt; row in data)
          {
            &lt;font color="blue"&gt;if&lt;/font&gt; (row &lt;font color="blue"&gt;is&lt;/font&gt; &lt;font color="blue"&gt;object&lt;/font&gt;[])
            {
              &lt;font color="blue"&gt;object&lt;/font&gt;[] columns = row as &lt;font color="blue"&gt;object&lt;/font&gt;[];
              &lt;font color="blue"&gt;foreach&lt;/font&gt; (&lt;font color="blue"&gt;object&lt;/font&gt; columnData in columns)
              {
                &lt;font color="blue"&gt;if&lt;/font&gt; (columnData != &lt;font color="blue"&gt;null&lt;/font&gt;)
                {
                  sb.Append(columnData);
                }
                sb.Append(&lt;font color="#aa2000"&gt;";"&lt;/font&gt;);
              }
              sb.Append(&lt;font color="#409090"&gt;Environment&lt;/font&gt;.NewLine);
            }
          }

          es.CloseWorkbook(sessionId, &lt;font color="blue"&gt;out&lt;/font&gt; status);
        }

        &lt;font color="#008080"&gt;File&lt;/font&gt;.WriteAllBytes(snapshotCacheFile, 
          &lt;font color="#008080"&gt;Encoding&lt;/font&gt;.Convert(&lt;font color="#008080"&gt;Encoding&lt;/font&gt;.UTF7, 
          &lt;font color="#008080"&gt;Encoding&lt;/font&gt;.GetEncoding(&lt;font color="#aa2000"&gt;"windows-1250"&lt;/font&gt;), 
          &lt;font color="#008080"&gt;Encoding&lt;/font&gt;.UTF7.GetBytes(sb.ToString())));
      }

      &lt;font color="blue"&gt;return&lt;/font&gt; snapshotCacheFile;
    }

    &lt;font color="blue"&gt;private&lt;/font&gt; &lt;font color="blue"&gt;void&lt;/font&gt; ExportSnapshotAsCSV()
    {
      &lt;font color="#0000ff"&gt;byte&lt;/font&gt;[] fileData = &lt;font color="#008080"&gt;File&lt;/font&gt;.ReadAllBytes(&lt;font color="blue"&gt;this&lt;/font&gt;.GetSnapshotFileCSV());

      &lt;font color="green"&gt;&lt;font color="green"&gt;// TODO: set meaningful name for the file (end user sees it)
&lt;/font&gt;&lt;/font&gt;      &lt;font color="blue"&gt;string&lt;/font&gt; filename = &lt;font color="#aa2000"&gt;"CSVData.csv"&lt;/font&gt;;
      &lt;font color="blue"&gt;this&lt;/font&gt;.Page.Response.Clear();
      &lt;font color="blue"&gt;this&lt;/font&gt;.Page.Response.AppendHeader(&lt;font color="#aa2000"&gt;&lt;font color="#aa2000"&gt;"Content-Disposition"&lt;/font&gt;&lt;/font&gt;, &lt;font color="#aa2000"&gt;&lt;font color="#aa2000"&gt;"attachment;filename="&lt;/font&gt;&lt;/font&gt; + filename);
      &lt;font color="blue"&gt;this&lt;/font&gt;.Page.Response.AddHeader(&lt;font color="#aa2000"&gt;&lt;font color="#aa2000"&gt;"LAST-MODIFIED"&lt;/font&gt;&lt;/font&gt;, DateTime.Now.ToString(&lt;font color="#aa2000"&gt;&lt;font color="#aa2000"&gt;"r"&lt;/font&gt;&lt;/font&gt;));
      &lt;font color="blue"&gt;this&lt;/font&gt;.Page.Response.ContentType = &lt;font color="#aa2000"&gt;"text/plain"&lt;/font&gt;;
      &lt;font color="blue"&gt;this&lt;/font&gt;.Page.Response.OutputStream.Write(fileData, 0, fileData.Length);
      &lt;font color="blue"&gt;this&lt;/font&gt;.Page.Response.Flush();
      &lt;font color="blue"&gt;this&lt;/font&gt;.Page.Response.End();
    }

    &lt;font color="blue"&gt;protected&lt;/font&gt; &lt;font color="blue"&gt;override&lt;/font&gt; &lt;font color="blue"&gt;void&lt;/font&gt; Render(&lt;font color="#409090"&gt;HtmlTextWriter&lt;/font&gt; writer)
    {
      &lt;font color="blue"&gt;this&lt;/font&gt;.RenderChildren(writer);

      &lt;font color="green"&gt;// Let's add our export iframe:
&lt;/font&gt;      writer.Write(&lt;font color="#aa2000"&gt;"&lt;/font&gt;&lt;font color="#800000"&gt;&amp;lt;iframe name=\"MyEWA\" src=\"about:blank\" width=\"1\" height=\"1\" /&amp;gt;"&lt;/font&gt;);
    }
  }
}&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;I'm not going to explain code since most of that is quite easily understandable... but if you have questions then post comment to this entry and I'll get back to you.&lt;/p&gt;
&lt;p&gt;You can probably see that I have added a lot of "&lt;font color="#008000"&gt;// TODO:&lt;/font&gt;"-markers to identify places you most likely will be doing some modifications if you plan to use my code. I also left some code blocks that I have tried and noticed that it doesn't work as you would expect. Good example is that you cannot change the caption / labels of the pivottable. You CAN do that in Excel but you cannot do that using Excel Services API. So in other words... this doesn't work:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;es.SetCellA1(sessionId, "Display", "A5", "My Pivottable caption", out status);&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;That is the reason why I have actually hidden that row. User sees still caption but it's just normal text that is formatted so that it looks like caption :-) But if I unhide &lt;em&gt;A5&lt;/em&gt; it would look like this:&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;div class="wlWriterSmartContent" id="scid:6960CE03-38FC-44df-87D4-FA4540212B06:0d3f2bc8-0f86-489a-87a0-b290295a0e6d" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;img src="http://blogs.msdn.com/photos/jannemattila/images/5931138/original.aspx" alt="" style="width:377px; height:83px;" /&gt;&lt;/div&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;But again... that caption isn't visible if you export Excel (row 5 is empty but user needs to &lt;em&gt;Unhide&lt;/em&gt; that row in order to see it):&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;div class="wlWriterSmartContent" id="scid:6960CE03-38FC-44df-87D4-FA4540212B06:283227ab-a1b7-4a9b-af3a-e47b41b44fd8" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;img src="http://blogs.msdn.com/photos/jannemattila/images/5931207/original.aspx" alt="" style="width:379px; height:79px;" /&gt;&lt;/div&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Another Excel tip that you need is Pivottable filters. Because if you don't set any filter you would get "(blank)" rows into table. That can be filtered away with &lt;em&gt;label filters&lt;/em&gt;:&lt;/p&gt;
&lt;div class="wlWriterSmartContent" id="scid:6960CE03-38FC-44df-87D4-FA4540212B06:b90c3b95-5eb8-433b-82b6-8e82d24c1833" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;img src="http://blogs.msdn.com/photos/jannemattila/images/5931285/original.aspx" alt="" style="width:482px; height:279px;" /&gt;&lt;/div&gt;
&lt;p&gt;Set "&lt;em&gt;Does Not Equal...&lt;/em&gt;" -filter to be empty:&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;div class="wlWriterSmartContent" id="scid:6960CE03-38FC-44df-87D4-FA4540212B06:766dd9c8-8eb3-43b9-9ec8-a2b4e3047b0b" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;img src="http://blogs.msdn.com/photos/jannemattila/images/5931297/original.aspx" alt="" style="width:405px; height:151px;" /&gt;&lt;/div&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;And after that you don't get those "(blank)" rows in your pivottable.&lt;/p&gt;
&lt;p&gt;If you're interestested that how did my solution look like inside VS:&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;div class="wlWriterSmartContent" id="scid:6960CE03-38FC-44df-87D4-FA4540212B06:2553f03b-e295-4517-8d22-ab1e9f5dc85d" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;img src="http://blogs.msdn.com/photos/jannemattila/images/5931506/original.aspx" alt="" style="width:247px; height:132px;" /&gt;&lt;/div&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;So I had resource files for &lt;em&gt;default&lt;/em&gt; language and &lt;em&gt;fi-FI&lt;/em&gt;. Since I used SharePoint &lt;em&gt;Web Part&lt;/em&gt; template (I like some much the F5 integration :-) I needed manually copy the &lt;em&gt;fi-FI&lt;/em&gt; folder under my projects &lt;em&gt;Debug&lt;/em&gt; folder under the web applications bin directory: &lt;em&gt;C:\Inetpub\wwwroot\wss\VirtualDirectories\1000\bin&lt;/em&gt;. I just wanted to mention this if you have issues with your resource files :-)&lt;/p&gt;
&lt;h3&gt;Performance?&lt;/h3&gt;
&lt;p&gt;I ended up doing a lot of static Excel files... so I think that it should be fast since now there isn't any database queries happening (not verified). BUT at least I managed to demonstrate that you could create static files so that if everything goes fine you should benefit from memory of your app servers. And if your data changes rarely you can easily create script that forces all the cache files to be created (just loops all the necessary HTTP requests). This would be trivial to implement. Here is one example call:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;http://demo1:1000/fi-FI/Sivut/MunEWA.aspx?ExportFormat=csv&amp;amp;File=MyEWA-fi-FI-Mountain.xlsx&amp;amp;Language=en-US&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;You can modify &lt;em&gt;ExportFormat&lt;/em&gt; and &lt;em&gt;File&lt;/em&gt; and &lt;em&gt;Language&lt;/em&gt; in order to get file that you want.&lt;/p&gt;
&lt;p&gt;And if you think this solution more deeply... actually you don't need even database at the production environment since you create static copies of Excels in another environment (i.e. publishing environment) :-) That would be another way to look at this solution... just distribute static Excel files between environments.&lt;/p&gt;
&lt;h3&gt;What's other possibilies I have?&lt;/h3&gt;
&lt;p&gt;You probably at least two more options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;OLAP + CUBE* -functions inside Excel 
&lt;ul&gt;
&lt;li&gt;You need to create ODC for the OLAP connection 
&lt;ul&gt;
&lt;li&gt;Store this in &lt;em&gt;Data Connection Library&lt;/em&gt; in SharePoint 
&lt;li&gt;You need to configure Single Single-On Service (SSO) to pass the credentials&lt;/li&gt;&lt;/ul&gt;
&lt;li&gt;You would have a better way to handle data 
&lt;li&gt;Downside: 
&lt;ul&gt;
&lt;li&gt;If you change filter =&amp;gt; new database request! 
&lt;li&gt;You will still have same issues with pivottable that with "old relational" pivottable&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;li&gt;UDF (User Defined Function) 
&lt;ul&gt;
&lt;li&gt;Create still all the data retrieval logic with .NET 
&lt;ul&gt;
&lt;li&gt;In Excel you would have something like this "=MyRetrieveData(Parameters!B2:Parameters:!B6)"&lt;/li&gt;&lt;/ul&gt;
&lt;li&gt;Downside: 
&lt;ul&gt;
&lt;li&gt;No preview :-( 
&lt;li&gt;Database requests&lt;/li&gt;&lt;/ul&gt;
&lt;li&gt;&lt;strong&gt;NOTE: &lt;/strong&gt;You can use this in your Excels even if you dynamically create the static instances! 
&lt;ul&gt;
&lt;li&gt;It could be probably good idea to use this for complex logic&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;I haven't validated those as detailed as I have this "static Excel instances" approach so I might be missing something important about the other approaches :-)&lt;/p&gt;
&lt;h3&gt;More information about Excel Services and Excel&lt;/h3&gt;
&lt;p&gt;As always... internet is full of stuff around Excel Services but you might want to check out at least these:&lt;/p&gt;
&lt;p&gt;&lt;a title="http://technet2.microsoft.com/Office/en-us/library/eea3ace8-0863-429a-b1e8-041254ed2fc41033.mspx?mfr=true" href="http://technet2.microsoft.com/Office/en-us/library/eea3ace8-0863-429a-b1e8-041254ed2fc41033.mspx?mfr=true"&gt;http://technet2.microsoft.com/Office/en-us/library/eea3ace8-0863-429a-b1e8-041254ed2fc41033.mspx?mfr=true&lt;/a&gt; -- White papers: Excel Services step-by-step guides&lt;/p&gt;
&lt;p&gt;&lt;a title="http://msdn2.microsoft.com/en-us/library/bb267252.aspx#Office2007ExcelServicesUnlimited_SharePointLists" href="http://msdn2.microsoft.com/en-us/library/bb267252.aspx#Office2007ExcelServicesUnlimited_SharePointLists"&gt;http://msdn2.microsoft.com/en-us/library/bb267252.aspx#Office2007ExcelServicesUnlimited_SharePointLists&lt;/a&gt; -- Extending the Excel Services Programmability Framework&lt;/p&gt;
&lt;p&gt;&lt;a title="http://www.microsoft.com/downloads/details.aspx?FamilyId=2D779CD5-EEB2-43E9-BDFA-641ED89EDB6C&amp;amp;displaylang=en" href="http://www.microsoft.com/downloads/details.aspx?FamilyId=2D779CD5-EEB2-43E9-BDFA-641ED89EDB6C&amp;amp;displaylang=en"&gt;http://www.microsoft.com/downloads/details.aspx?FamilyId=2D779CD5-EEB2-43E9-BDFA-641ED89EDB6C&amp;amp;displaylang=en&lt;/a&gt; -- Excel 2007 Document: Designing SQL Server 2005 Analysis Services Cubes for Excel 2007 PivotTables&lt;/p&gt;
&lt;p&gt;&lt;a title="http://blogs.msdn.com/cumgranosalis/" href="http://blogs.msdn.com/cumgranosalis/"&gt;http://blogs.msdn.com/cumgranosalis/&lt;/a&gt; -- Cum Grano Salis&lt;/p&gt;
&lt;p&gt;&lt;a title="http://blogs.msdn.com/luisbeonservices/" href="http://blogs.msdn.com/luisbeonservices/"&gt;http://blogs.msdn.com/luisbeonservices/&lt;/a&gt; -- LuisBE on Services&lt;/p&gt;
&lt;p&gt;&lt;a title="http://blogs.msdn.com/excel/" href="http://blogs.msdn.com/excel/"&gt;http://blogs.msdn.com/excel/&lt;/a&gt; -- The team blog for Microsoft Excel and Excel Services&lt;/p&gt;
&lt;p&gt;&lt;a title="http://msdn2.microsoft.com/en-us/library/bb758869.aspx" href="http://msdn2.microsoft.com/en-us/library/bb758869.aspx"&gt;http://msdn2.microsoft.com/en-us/library/bb758869.aspx&lt;/a&gt; -- Chapter 1: An Introduction to Excel Services&lt;/p&gt;
&lt;p&gt;&lt;a title="http://msdn2.microsoft.com/en-us/library/bb758868.aspx" href="http://msdn2.microsoft.com/en-us/library/bb758868.aspx"&gt;http://msdn2.microsoft.com/en-us/library/bb758868.aspx&lt;/a&gt; -- Chapter 3: Excel Web Access&lt;/p&gt;
&lt;h3&gt;Final words&lt;/h3&gt;
&lt;p&gt;Well that ended up being looong post :-) I'll probably still work on this subject so I might get back with follow-ups. I'll probably do some performance tests so that I'll get some indications that how well this does work.&lt;/p&gt;
&lt;p&gt;This subject is actually quite complex. I don't consider this case as solved... I just consider this as good kickstart :-) There are still many open questions like: "&lt;em&gt;What's the best place to do translations?&lt;/em&gt;" (and many more). Well I don't have answer to that since I think it's not that black and white :-) You may see that some are easy to translate in DB but same are too hard (or database model doesn't support it) and then you need to do that somewhere else.&lt;/p&gt;
&lt;p&gt;If you plan to use this code you first need to generalize it since my solution is quite fixed to one certain Excel file. But I think that is actually quite easy task and I'll let you work on that.&lt;br&gt;&lt;/p&gt;
&lt;p&gt;Anyways... Happy hacking!&lt;br&gt;&lt;br&gt;J&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=5939871" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/jannemattila/archive/tags/Microsoft+Office+SharePoint+Server+2007/default.aspx">Microsoft Office SharePoint Server 2007</category><category domain="http://blogs.msdn.com/jannemattila/archive/tags/Programming/default.aspx">Programming</category><category domain="http://blogs.msdn.com/jannemattila/archive/tags/Excel+Services/default.aspx">Excel Services</category></item></channel></rss>