File upload controls are important part from many web applications. Upload components enables you to provide users with a way to send a file from their computer to the server. These controls are useful for allowing users to upload pictures, text files, or other files.
The Infragistics Ignite UI suite includes the File Upload Control (igUpload) that you can use to offer to your users all features expected from upload components. If you prefer to use C# you can use the Html helper in APS.NET MVC to get it running in no time. File Upload is available also for Infragistics ASP.Net Web Forms components as Web Upload (it an igUpload wrapper ).
In several posts you will learn how to use Ignite UI Upload Control in specific cases when you need better performance ( using igUpload in Web Garden, Web Farm, Cloud solutions / Microsoft Azure ) . Performance could be an issue when you need to backup many large files using File Upload. Reliability is another reason to use similar solutions.
We will not do an overview of the igUpload features. You can find detailed information about Ignite UI upload functionalities in Infragistics documentation or www.igniteui.com
This article is focused on how to use Ignite UI upload control in applications, configured as Web Gardens. If you have no experience with Web Gardens – don’t worry – this post also makes an overview how to configure one web application to use multiple worker processes ( Web Garden) in IIS, what is the difference between Web Garden , Web Farm, cloud applications and more…
What is IIS
IIS (Internet Information Server) from Microsoft is used to host your ASP.NET Web applications. IIS has it’s own ASP.NET Process Engine to handle the ASP.NET request. So, when a request comes from client to server, IIS takes that request and process it and send response back to clients.
Worker processes are a way of segmenting the execution of your website across multiple exe's. You do this for a couple of reasons, one if one of the workers gets clobbered by run time issues it doesn't take the others down.
- Worker Process
Worker Process (w3wp.exe) runs the ASP.Net application in IIS. This process is responsible to manage all the request and response that are coming from client system. All the ASP.Net functionality runs under the scope of worker process
- Application pool
Application pool is the container of worker process. Application pools is used to separate sets of IIS worker processes that share the same configuration. Application pools enables a better security, reliability, and availability for any web application. The worker process serves as the process boundary that separates each application pool so that when one worker process or application is having an issue or recycles, other applications or worker processes are not affected.
Web Farm
You may need to use multiple servers to host the application and divide the traffic among them. This is called “Web Farm”. So when you are hosting your single web site on multiple web servers over load balancer is called “Web Farm”. We will cover more details, related to the web farms in the next part of this article.
Web Garden
By default, each Application pool contains a single worker process. Application which contains the multiple worker process is called “Web Garden”. Below is the typical diagram for a web garden application.
So, a Web application hosted on multiple servers and access based on the load on servers is called Web Farms and when a single application pool contains multiple Worker processes, it is called a web garden.
Ignite UI Upload Implementation for Web Garden:
The current implementation uses Visual Studio 2013, ASP.Net MVC 5 and Ignite UI 14.1 . The igUpload control is updated to use cistom dictionary providers for Web Farm / Web Garden scenarios - It was not possible to use it in previous 13.x versions of Ignite UI of you have the latest service releases.
When application is configured to use multiple worker processes, the main issue is how to sync information about the uploading files. This functionality is supported via CustomDictionaryProvider.
CustomDictionaryProvider configures a third party dictionary provider (the structure which holds the metadata for the currently uploading files).
This setting is specifically designed for Web Farm/Web Garden scenarios where a common file metadata should be shared between multiple machines/processes.
This setting expects a name of a type which implements ISafeDictionary<string, UploadInfo> interface.
There are different possible approaches to keep your metadata independent from different processes. On of possible solutions includes implementation of the web service (WCF service) where to keep upload info metadata. It could run in separate IIS application pool, where
WPF Service (FileUploadSvc):
Implementation includes simple WCF application.
- IUploadService interface ( IUploadService.cs )
1:using System;
2:using System.Collections.Generic;
3:using System.ServiceModel;
4:using Infragistics.Web.Mvc;
5:
6:namespace FileUploadSvc
7: {
8: [ServiceContract]
9:publicinterface IUploadService
10: {
11: [OperationContract]
12:void SetData(Dictionary<string, UploadInfo> dict);
13:
14: [OperationContract]
15: Dictionary<string, UploadInfo> GetData();
16:
17: [OperationContract]
18:bool RemoveData(string key);
19: }
20: }
- UploadService.svc.cs
Code below shows the implementation of IUploadService , where the most important is how to manage dictionaries with upload information ( upload metadata structure is defined in UploadInfo type )
1:using System;
2:using System.Collections.Generic;
3:using System.Linq;
4:using System.ServiceModel;
5:using Infragistics.Web.Mvc;
6:
7:namespace FileUploadSvc
8: {
9:
10:
11: [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
12:publicclass UploadService : IUploadService
13: {
14:
15: Dictionary<string, UploadInfo> _dictFiles = new Dictionary<string, UploadInfo>();
16:
17:publicvoid SetData(Dictionary<string, UploadInfo> dict)
18: {
19:try
20: {
21:if (dict != null)
22: {
23:this._dictFiles = Merge(new Dictionary<string, UploadInfo>[] { dict, this._dictFiles });
24: }
25: }
26:catch (Exception ex)
27: {
28: Console.Write(ex.Message);
29: }
30: }
31:
32:publicbool RemoveData(string key)
33: {
34:bool isRemoved = false;
35:if (this._dictFiles != null&& this._dictFiles.ContainsKey(key))
36: {
37: isRemoved = this._dictFiles.Remove(key);
38: }
39:return isRemoved;
40: }
41:
42:public Dictionary<string, UploadInfo> Merge(Dictionary<string, UploadInfo>[] dictionaries)
43: {
44:return dictionaries.SelectMany(x => x)
45: .ToLookup(pair => pair.Key, pair => pair.Value)
46: .ToDictionary(group => group.Key, group => group.First());
47: }
48:
49:public Dictionary<string, UploadInfo> GetData()
50: {
51:returnthis._dictFiles;
52: }
53:
54:
55: }
56: }
Upload implementation (ASP.Net MVC 5 Application)
- ISafeDictionary interface
Below is shown ISafeDictionary interface
1:publicinterface ISafeDictionary<TKey, TValue> : IDictionary<TKey, TValue>, ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>, IEnumerable
2: {
3:// Summary:
4:// Check if the key exists in the dictionary, if not adds the value
5://
6:// Parameters:
7:// key:
8://
9:// value:
10:bool CheckAndAdd(TKey key, TValue value);
11: }
- CustomSafeDictionary class
Implementation of Serialization in CustomSafeDictionary (as shown below)
1:#region Serialization
2:private Dictionary<string, UploadInfo> Dictionary
3: {
4: get
5: {
6:returnthis.Deserialize();
7: }
8: }
9:
10:private Dictionary<string, UploadInfo> Deserialize()
11: {
12: UploadService.UploadServiceClient client = new UploadService.UploadServiceClient();
13:return client.GetData();
14: }
15:
16:privatevoid Serialize(Dictionary<string, UploadInfo> d)
17: {
18: UploadService.UploadServiceClient client = new UploadService.UploadServiceClient();
19: client.SetData(d);
20: }
21:#endregion
The whole CustomSafeDictionary class code is available below:
1: [Serializable]
2:publicclass CustomSafeDictionary : ISafeDictionary<string, UploadInfo>
3: {
4:
5:#region Members
6:privatereadonlyobject syncRoot = newobject();
7:private Dictionary<string, UploadInfo> _dictionary;
8:#endregion
9:
10:
11:public CustomSafeDictionary()
12: {
13:this._dictionary = new Dictionary<string, UploadInfo>();
14: Serialize(this._dictionary);
15: }
16:
17:#region Serialization
18:private Dictionary<string, UploadInfo> Dictionary
19: {
20: get
21: {
22:returnthis.Deserialize();
23: }
24: }
25:
26:private Dictionary<string, UploadInfo> Deserialize()
27: {
28: UploadService.UploadServiceClient client = new UploadService.UploadServiceClient();
29:return client.GetData();
30: }
31:
32:privatevoid Serialize(Dictionary<string, UploadInfo> d)
33: {
34: UploadService.UploadServiceClient client = new UploadService.UploadServiceClient();
35: client.SetData(d);
36: }
37:#endregion
38:
39:#region Properties
40:#region Keys
41:/// <summary>
42:/// Returns the collection of keys
43:/// </summary>
44:public ICollection<string> Keys
45: {
46: get
47: {
48: ICollection<string> keys;
49:lock (syncRoot)
50: {
51: keys = this.Dictionary.Keys;
52: }
53:return keys;
54: }
55: }
56:#endregion
57:
58:#region Values
59:/// <summary>
60:/// Gets the collection containing the values
61:/// </summary>
62:public ICollection<UploadInfo> Values
63: {
64: get
65: {
66: ICollection<UploadInfo> values;
67:lock (syncRoot)
68: {
69: values = this.Dictionary.Values;
70: }
71:return values;
72: }
73: }
74:#endregion
75:
76:#regionthis[string key]
77:/// <summary>
78:/// Gets or sets the value associated with the specified key.
79:/// </summary>
80:/// <param name="key"></param>
81:/// <returns></returns>
82:public UploadInfo this[string key]
83: {
84: get
85: {
86: UploadInfo value;
87:lock (syncRoot)
88: {
89:value = this.Dictionary[key];
90: }
91:returnvalue;
92: }
93: set
94: {
95:lock (syncRoot)
96: {
97:this._dictionary = this.Dictionary;
98:this._dictionary[key] = value;
99:this.Serialize(this._dictionary);
100:
101: }
102: }
103: }
104:#endregion
105:
106:#region Count
107:/// <summary>
108:/// Gets the number of key/value pairs in the dictionary
109:/// </summary>
110:publicint Count
111: {
112: get
113: {
114:int count = 0;
115:lock (syncRoot)
116: {
117: count = this.Dictionary.Count;
118: }
119:return count;
120: }
121: }
122:#endregion
123:
124:#region IsReadOnly
125:/// <summary>
126:/// Returns whether the dictionary is read only
127:/// </summary>
128:publicbool IsReadOnly
129: {
130: get { returnfalse; }
131: }
132:#endregion
133:#endregion
134:
135:#region Methods
136:#region IDictionary<string,UploadInfoMembers>
137:/// <summary>
138:/// Adds the specified key and value to the dictionary
139:/// </summary>
140:/// <param name="key"></param>
141:/// <param name="value"></param>
142:publicvoid Add(string key, UploadInfo value)
143: {
144:lock (syncRoot)
145: {
146:this._dictionary = this.Dictionary;
147:this._dictionary.Add(key, value);
148:this.Serialize(this._dictionary);
149: }
150: }
151:
152:/// <summary>
153:/// Check if the key exists in the dictionary, if not adds the value
154:/// </summary>
155:/// <param name="key"></param>
156:/// <param name="value"></param>
157:/// <returns></returns>
158:publicbool CheckAndAdd(string key, UploadInfo value)
159: {
160:bool isAdded = false;
161:lock (syncRoot)
162: {
163:if (!this.Dictionary.ContainsKey(key))
164: {
165:this._dictionary = this.Dictionary;
166:this._dictionary.Add(key, value);
167:this.Serialize(this._dictionary);
168: isAdded = true;
169: }
170: }
171:
172:return isAdded;
173: }
174:
175:/// <summary>
176:/// Check if the key exists in dictionary, if not adds the value
177:/// </summary>
178:/// <param name="keyValuePair"></param>
179:/// <returns></returns>
180:publicbool CheckAndAdd(KeyValuePair<string, UploadInfo> keyValuePair)
181: {
182:bool isAdded = false;
183:lock (syncRoot)
184: {
185:if (!this.Dictionary.ContainsKey(keyValuePair.Key))
186: {
187: Add(keyValuePair);
188: isAdded = true;
189: }
190: }
191:
192:return isAdded;
193: }
194:
195:/// <summary>
196:/// Check if the dictionary contains the specified key
197:/// </summary>
198:/// <param name="key"></param>
199:/// <returns></returns>
200:publicbool ContainsKey(string key)
201: {
202:bool isContains = false;
203:lock (syncRoot)
204: {
205: isContains = this.Dictionary.ContainsKey(key);
206: }
207:return isContains;
208: }
209:
210:
211:/// <summary>
212:/// Removes from the dictionary item with the specified key
213:/// </summary>
214:/// <param name="key"></param>
215:/// <returns></returns>
216:publicbool Remove(string key)
217: {
218:lock (syncRoot)
219: {
220: UploadService.UploadServiceClient client = new UploadService.UploadServiceClient();
221:
222:return client.RemoveData(key);
223: }
224: }
225:
226:publicbool TryGetValue(string key, out UploadInfo value)
227: {
228:lock (syncRoot)
229: {
230:this._dictionary = this.Dictionary;
231:returnthis._dictionary.TryGetValue(key, outvalue);
232: }
233: }
234:
235:
236:#endregion
237:
238:#region ICollection<KeyValuePair<string,UploadInfo>Members
239:/// <summary>
240:/// Adds the item to collection
241:/// </summary>
242:/// <param name="item"></param>
243:publicvoid Add(KeyValuePair<string, UploadInfo> item)
244: {
245:lock (syncRoot)
246: {
247:this._dictionary = this.Dictionary;
248: ((ICollection<KeyValuePair<string, UploadInfo>>)this._dictionary).Add(item);
249:this.Serialize(this._dictionary);
250: }
251: }
252:
253:/// <summary>
254:/// Removes all keys and values from the dictionary
255:/// </summary>
256:publicvoid Clear()
257: {
258:lock (syncRoot)
259: {
260:this._dictionary = this.Dictionary;
261:this._dictionary.Clear();
262:this.Serialize(this._dictionary);
263: }
264: }
265:
266:/// <summary>
267:/// Check whether the dictionary contains the specific item
268:/// </summary>
269:/// <param name="item"></param>
270:/// <returns></returns>
271:publicbool Contains(KeyValuePair<string, UploadInfo> item)
272: {
273:return ((ICollection<KeyValuePair<string,
274: UploadInfo>>)this.Dictionary).Contains(item);
275: }
276:
277:/// <summary>
278:/// Copies the dictionary KeyCollection
279:/// elements to an existing one-dimensional System.Array, starting at the specified array index.
280:/// </summary>
281:/// <param name="array"></param>
282:/// <param name="arrayIndex"></param>
283:publicvoid CopyTo(KeyValuePair<string, UploadInfo>[] array, int arrayIndex)
284: {
285:lock (syncRoot)
286: {
287:this._dictionary = this.Dictionary;
288: ((ICollection<KeyValuePair<string, UploadInfo>>)this._dictionary).CopyTo(array,
289: arrayIndex);
290:this.Serialize(this._dictionary);
291: }
292: }
293:
294:/// <summary>
295:/// Removes the value with the specified key from the dictionary.
296:/// </summary>
297:/// <param name="item"></param>
298:/// <returns></returns>
299:publicbool Remove(KeyValuePair<string, UploadInfo> item)
300: {
301:lock (syncRoot)
302: {
303:this._dictionary = this.Dictionary;
304:return ((ICollection<KeyValuePair<string,
305: UploadInfo>>)this._dictionary).Remove(item);
306:this.Serialize(this._dictionary);
307: }
308: }
309:
310:#endregion
311:
312:#region IEnumerable<KeyValuePair<string,UploadInfo>Members
313:/// <summary>
314:/// Returns an enumerator that iterates through the collection.
315:/// </summary>
316:/// <returns></returns>
317:public IEnumerator<KeyValuePair<string, UploadInfo>> GetEnumerator()
318: {
319:return ((ICollection<KeyValuePair<string, UploadInfo>>)this.Dictionary).GetEnumerator();
320: }
321:
322:#endregion
323:
324:#region IEnumerable Members
325:/// <summary>
326:/// Returns an enumerator that iterates through a collection.
327:/// </summary>
328:/// <returns>An System.Collections.IEnumerator object that can be used to iterate through the collection</returns>
329: System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
330: {
331:return ((System.Collections.IEnumerable)this.Dictionary).GetEnumerator();
332: }
333:
334:#endregion
335:#endregion
336: }
- Configuration:
- Web.config file
The appSettings section
1:<appSettings>
2: ....
3:<addkey="fileUploadPath"value="~/Uploads"/>
4:<addkey="maxFileSizeLimit"value="5194304"/>
5:<addkey="bufferSize"value="56384"/>
6:<addkey="CustomDictionaryProvider"value="IgUploadMvc03.CustomSafeDictionary, IgUploadMvc03"/>
7:</appSettings>
The webServer section
1:<system.webServer>
2:<modulesrunAllManagedModulesForAllRequests="true">
3:<addname="IGUploadModule"type="Infragistics.Web.Mvc.UploadModule"
4:preCondition="managedHandler"/>
5:</modules>
6:<handlers>
7:<addname="IGUploadStatusHandler"path="IGUploadStatusHandler.ashx"verb="*"
8:type="Infragistics.Web.Mvc.UploadStatusHandler"preCondition="integratedMode"/>
9:</handlers>
10: ....
11:</system.webServer>
- RouteConfig class
1:publicclass RouteConfig
2: {
3:publicstaticvoid RegisterRoutes(RouteCollection routes)
4: {
5: routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
6: routes.IgnoreRoute("IGUploadStatusHandler.ashx");
7: routes.MapRoute(
8: name: "Default",
9: url: "{controller}/{action}/{id}",
10: defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
11: );
12: }
13: }
- Controllers ( MVC project)
1:public ActionResult Upload()
2: {
3: ViewBag.Message = "Your upload page.";
4:
5:return View();
6: }
7:
8:
9:public ActionResult UploadMvc()
10: {
11: ViewBag.Message = "Your upload MVC page.";
12:
13:return View();
14: }
- Views:
- HTML5 / jQuery implementation (Upload view )
1:<!DOCTYPEhtml>
2:
3:<html>
4:<head>
5:<title></title>
6:<linkhref="http://cdn-na.infragistics.com/jquery/20141/latest/css/themes/infragistics/infragistics.theme.css"rel="stylesheet"/>
7:<linkhref="http://cdn-na.infragistics.com/jquery/20141/latest/css/structure/infragistics.css"rel="stylesheet"/>
8:
9:<scriptsrc="http://modernizr.com/downloads/modernizr-latest.js"></script>1:
2:<script src="http://code.jquery.com/jquery-1.9.1.min.js">1:</script>
2:<script src="http://code.jquery.com/ui/1.10.3/jquery-ui.min.js">1:</script>
2:
3:<!-- Ignite UI Required Combined JavaScript Files -->
4:<script src="http://cdn-na.infragistics.com/jquery/20141/latest/js/infragistics.core.js">1:</script>
2:<script src="http://cdn-na.infragistics.com/jquery/20141/latest/js/infragistics.lob.js">1:</script>
2:
3:</head>
4:<body>
5:<link href="http://cdn-na.infragistics.com/jquery/20141/latest/css/themes/infragistics/infragistics.theme.css" rel="stylesheet" />6:<link href="http://cdn-na.infragistics.com/jquery/20141/latest/css/structure/infragistics.css" rel="stylesheet" />7:
8:<style type="text/css">9: .container-info, .error-info {
10: margin: 10px 0;
11: font-weight: bold;
12: }
13:
14: .error-info {
15: color: #FF0000;
16: }
17:</style>
18:
19:<script src="http://modernizr.com/downloads/modernizr-latest.js">1:</script>
2:<script src="http://code.jquery.com/jquery-1.9.1.min.js">1:</script>
2:<script src="http://code.jquery.com/ui/1.10.3/jquery-ui.min.js">1:</script>
2:
3:<!-- Ignite UI Required Combined JavaScript Files -->
4:<script src="http://cdn-na.infragistics.com/jquery/20141/latest/js/infragistics.core.js">1:</script>
2:<script src="http://cdn-na.infragistics.com/jquery/20141/latest/js/infragistics.lob.js">1:</script>
2:
3:</head>
4:<body>
5:
6:<div id="igUpload1"></div>7:<div id="error-message" style="color: #FF0000; font-weight: bold;"></div>8:<script>
9:
10: $(function () {11: $("#igUpload1").igUpload({12: mode: 'multiple',13: maxUploadedFiles: 4,
14: maxSimultaneousFilesUploads: 2,
15: autostartupload: true,16: progressUrl: "/IGUploadStatusHandler.ashx",17: onError: function (e, args) {18: showAlert(args);
19: }
20: });
21: });
22:
23:function showAlert(args) {24: $("#error-message").html(args.errorMessage).stop(true, true).fadeIn(500).delay(3000).fadeOut(500);25: }
26:
27://more optional code28:
</script>
10:
11:</body>
12:</html>
- Razor implementation (UploadMvc view )
1:@using Infragistics.Web.Mvc
2:
3: @{
4: Layout = null;
5: }
6:
7:<!DOCTYPE html>
8:
9:<html>
10:<head>
11:<meta name="viewport" content="width=device-width" />
12:<title>IgUpload MVC Helper</title>
13:<!-- Ignite UI Required Combined CSS Files -->
14:<link href="http://cdn-na.infragistics.com/jquery/20141/latest/css/themes/infragistics/infragistics.theme.css" rel="stylesheet" />
15:<link href="http://cdn-na.infragistics.com/jquery/20141/latest/css/structure/infragistics.css" rel="stylesheet" />
16:
17:<script src="http://modernizr.com/downloads/modernizr-latest.js"></script>
18:<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
19:<script src="http://code.jquery.com/ui/1.10.3/jquery-ui.min.js"></script>
20:
21:<!-- Ignite UI Required Combined JavaScript Files -->
22:<script src="http://cdn-na.infragistics.com/jquery/20141/latest/js/infragistics.core.js"></script>
23:<script src="http://cdn-na.infragistics.com/jquery/20141/latest/js/infragistics.lob.js"></script>
24:
25:</head>
26:<body>
27:<div>
28: @(
29: Html.Infragistics().Upload()
30: .ID("igUpload1")
31: .Mode(UploadMode.Single)
32: .AutoStartUpload(true)
33: .ProgressUrl(Url.Content("~/IGUploadStatusHandler.ashx"))
34: .ControlId("serverID1")
35: .Render()
36: )
37:
38:<div id="error-message" style="color: #FF0000; font-weight: bold;"></div>
39:
40:<script type="text/javascript">
41: $(function () {
42: $("#igUpload1").bind({
43: iguploadonerror: function (e, args) {
44: $("#error-message").html(args.errorMessage).stop(true, true).fadeIn(500).delay(3000).fadeOut(500);
45: }
46: });
47: });
48:</script>
49:</div>
50:</body>
51:</html>
ASP.Net Web Forms solution:
If you need to use ASP.Net Web Forms application, the only one difference is *aspx file, where you should add a WebUpload ASP.Net control
*.aspx file:
1:<div>
2:<divid="main"style="margin: 50px;">
3:<divid="error-message"style="color: #FF0000; font-weight: bold;">
4:</div>
5:<ig:WebUploadAutoStartUpload="true"ID="IGUpload"runat="server"ClientIDMode="Static"
6:LabelUploadButton="Browse PDF"LabelAddButton="Browse PDF"FileSizeMetric="KBytes"ProgressUrl="IGUploadStatusHandler.ashx"Style="width: auto;">
7:<AllowedExtensions>
8:<ig:FileUploadExtensionExtension="pdf"/>
9:<ig:FileUploadExtensionExtension="PDF"/>
10:<ig:FileUploadExtensionExtension="Pdf"/>
11:<ig:FileUploadExtensionExtension="PDf"/>
12:<ig:FileUploadExtensionExtension="pDF"/>
13:<ig:FileUploadExtensionExtension="pDf"/>
14:<ig:FileUploadExtensionExtension="pdF"/>
15:<ig:FileUploadExtensionExtension="PdF"/>
16:<ig:FileUploadExtensionExtension="PDf"/>
17:</AllowedExtensions>
18:<FileExtensionIcons>
19:<ig:FileUploadExtensionIconDefault="True">
20:<Extensions>
21:<ig:FileUploadExtensionExtension="pdf"/>
22:</Extensions>
23:</ig:FileUploadExtensionIcon>
24:</FileExtensionIcons>
25:<ClientEventsFileUploaded="fileUploaded"/>
26:<ClientEventsFileSelecting="fileSelecting"/>
27:<ClientEventsFileSelected="fileSelected"/>
28:<ClientEventsOnError="onErrorHandler"/>
29:</ig:WebUpload>
30:<asp:HiddenFieldID="filePath"ClientIDMode="Static"runat="server"/>
31:</div>
32:<ahref="#"id="btnImportDocsAdd"class="ui-button ui-state-default ui-corner-all"style="display:none;"
33:runat="server"clientidmode="static"><spanclass="ui-icon ui-icon-plus"></span>Move Documents</a>
34:</div>
Configuation in web.config is identical with this one for ASP.Net MVC project
IIS configuration ( IIS 7.x and IIS 8.x)
- Create /set application pools
IIS Management Console –> Application Pools –> Add Application Pool
Select the pool and choose “Advanced Settings”.
Add a new application pool ( IgUploadMvc) .
Select the created new application pool and choose “Advanced Settings”
- Check the setting for our ASP.Net MVC project (IgUploadMVC03)
Manage Application –> Advanced Settimgs->Application Pool
- Check the setting for WCF application project (FIleUploadSvc)
It is important when we need multiple worker processes for Ignite UI Upload component to have different application pools for the MVC application, including upload control and your WCF service.
WCF service is used to keep upload information for each file
Ensure that the application pool is different (even if it is a default application pool / DefaultAppPool ) and its Maximum Worker Processes is set to 1
Application pool default settings:
Sample application: ASP.Net MVC 5 project.
If you want to test your application in debug mode you need to set in Web properties to use Local IIS or External Host ( IIS Express cannot allow you to test multiple worker processes )
Sample application , available for download here , has two views to demonstrate Ignite UI file upload , one with pure jQuery implementation (Upload view) and another one with MVC helper (UploadMvc view)
Screens below demonstrate how to upload file using jQuery implementation ( view with MVC helper provides identical functionalities)
Initial state of the upload
Choose files
Upload progress
Final screen state
Uploaded files
We would be able to summarize that you need to use igUpload with multiple worker roles you need to:
- Implement a CustomDuctionaryProvider
1.1 This provider should maintain upload metadata out of the same application pool where works your application.
1.2 One simple implementation is via WCF service that works in separate application pool (This pool should have maximum worker processes per application set to 1. Otherwise you can have metadata for each worker process that is not consistent with the metadata for other worker processes) - Set your CustomDictionaryProvider in the Web.config of your ASP.Net MVC / Web Forms application
This implementation is mainly for Web Gardens , but it could work for Web Farms / Cloud solutions as you will see in the next parts of this article.
Sample project, used for this blog could be downloaded here:
Click on this image to get a fully support trial version of Infragistics Ignite UI controls:
To view all the samples and code for HTML, MVC & ASP.NET, click here:
Follow news from Infragistics for more information about new Infragistics products.
As always, you can follow us on Twitter @mihailmateev and @Infragistics and stay in touch on Facebook,Google+andLinkedIn!