The ways to receive complex parameters in ASP.NET
- 1. WebHandler - the simplest and universal way to receive any parameters in ASP.NET.
- 2. WebAPI - modern alternative way to receive complex parameter without model.
- 3. Receive data in MVC controller without model (by FormCollection or by Name).
- 4. Receive data in MVC with model.
- 5. Custom model provider.
- 6. Define parameters as raw stream.
- 7. Get/Post request to controller from Javascript.
- 8. Use Ajax/WebApi Syns/Async request/response.
- Update to NET 8.0
There are some choice to receive parameters in ASP.NET. In this page I'm describe most of it. This is real workable code, therefore as example to first part code below, I'll use this form.
9: <form role="form" name="resumeform" id="resumeform" method="post" enctype="multipart/form-data" action="/api/Upload/PostResumeData">
10: <div class="col-md-1 panel1" style="border:none">
11: </div>
12: @Html.Partial("~/Views/Resume/PostSetSkillPanel.vbhtml")
13: <div class="col-md-7 panel1">
14: <h2>Please fill all fields in your public resume </h2>
15: <div style="max-height: 750px; min-height:750px; overflow: auto;">
16: <div class="form-group">
17: <label for="Title"><span style="color:red">*</span> Title of your bean </label>
18: <input class="form-control" id="title" name="title" placeholder="No more than 100 chars.">
19: </div>
20: <div class="form-group">
21: <label for="InputPDFFile">Upload PDF files with your resume</label>
22: <input type="file" class="form-control-file" id="InputPDFFile" name="InputPDFFile">
23: <p class="help-block">This pdf files not will be parsed or changed.</p>
24: </div>
25: <div class="form-group">
26: <label for="InputAvaFile">Upload your Avatar (if necessary)</label>
27: <input type="file" class="form-control-file" id="InputAvaFile" name="InputAvaFile">
28: <p class="help-block">Will be reduced to 100x100 px</p>
29: </div>
30: <div class="form-group">
31: <label for="Short-description"><span style="color:red">*</span> Enter description for customer </label>
32: <textarea class="form-control" id="Short-description" rows="7" placeholder="No more than 1000 chars." name="Short-description"></textarea>
33: </div>
34: <div class="form-group">
35: <label for="Publiccontacts"><span style="color:red">*</span> Enter your public contacts for customer </label>
36: <input class="form-control" id="Publiccontacts" placeholder="Any your public contact in free form, No more than 100 chars." name="Publiccontacts"">
37: </div>
38: <div class="form-group">
39: <label for="AdminContacts">Enter your email for Sign in to this site. </label>
40: <input type="email" class="form-control" id="AdminContacts" placeholder="We sent password to this email." name="AdminContacts">
41: <span style="color:red">*</span> or <br />
42: <label for="Publiccontacts">Sign In using another account</label>
43: <a class="oauth" alt="Sign in using Github" title="Sign in using Github" href="/script/Membership/OAuthLogOn.aspx?auth=GitHub"><img src="/Images/octicons_github-lg.png" style="vertical-align:middle;padding-right:3px;border:0;"></a>
44: <a class="oauth" alt="Sign in using Linkedin" title="Sign in using Linkedin" href="/script/Membership/OAuthLogOn.aspx?auth=LinkedIn"><img src="/Images/linkedin-lg.png" style="vertical-align:middle;padding-right:3px;border:0;"></a>
45: <a class="oauth" alt="Sign in using Facebook" title="Sign in using Facebook" href="/script/Membership/OAuthLogOn.aspx?auth=Facebook"><img src="/Images/facebook-lg.png" style="vertical-align:middle;padding-right:3px;border:0;"></a>
46: <a class="oauth" alt="Sign in using Google" title="Sign in using Google" href="/script/Membership/OAuthLogOn.aspx?auth=Google"><img src="/Images/google-plus-lg.png" style="vertical-align:middle;padding-right:3px;border:0;"></a>
47: <a class="oauth" alt="Sign in using Microsoft" title="Sign in using Microsoft" href="/script/Membership/OAuthLogOn.aspx?auth=Microsoft"><img src="/Images/microsoft-lg.png" style="vertical-align:middle;padding-right:3px;border:0;"></a>
48: </div>
49: <button id="PostResume" name="PostResume" type="submit" class="btn btn-primary">Post Resume</button>
50: </div>
51: </div>
52: </form>
53: </div>
54:
1. WebHandler - the simplest and universal way to receive any parameters in ASP.NET.
First, simplest and common choice is exclude any specific Microsoft complicated superstructure. And receive form parameters with simple ASP.NET Handler (.ASHX). This way I use in most situation when I have difficulties with built in Microsoft processing of parameters. And this is oldest way to receive parameters in ASP.NET MVC, what exist in ASP.NET over 15 years.
- Пакетный загрузчик файлов на сайт. this it a handler for processing multipart/form-data, based on MultipartParser http://multipartparser.codeplex.com/
- Сховище графіки на SQL FileStream та канал браузеру multipart/form-data. - the same way, this code used OpenSource library HttpMultipartParser.MultipartFormDataParser.
- Cropper світлин сайту. - this is common use of ASHX-handler, in this page I'm describe universal handler what can be calling by both way - from AJAX and from MVC controller.
- Bla-Bla-Car Server. and ???????? ?? Google-maps API, ?????????????????????????????????? ?? Dynamic LINQ Expression. in this two pages I decide use WebHandler instead WebAPI, because this is simplest way to reach needed result.
- Как сделать простейший Web-handler - формирующий XML или JSON. this is a simplest and common way to create XML, opposite to complex microsoft way, named WebMethod, what I'm decribed in page SPA-page ???? Classic ASP.NET ???? jQuery.
Complex parameters usually reading by MultipartParser and there are two way to read simple POST parameters. First way, if POST-parameters packed with rules content type application/x-www-form-urlencoded, it usually receive as context.Request.Form("Prm1"), otherwise its can read as raw stream, like below (this is template of security activator, that receive GUID-string and return 20-chars code for activation program, but in reality, of cource, string 15 is more complex).
1: Imports System.Web
2: Imports System.Web.Services
3:
4: Public Class GetCode
5: Implements System.Web.IHttpHandler
6:
7: Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
8: Dim Str1 As String
9: Using reader = New IO.StreamReader(context.Request.InputStream)
10: Str1 = reader.ReadToEnd()
11: End Using
12: If Not String.IsNullOrWhiteSpace(Str1) Then
13: Dim Hash As Byte()
14: Using Md5 As System.Security.Cryptography.MD5 = System.Security.Cryptography.MD5.Create()
15: Hash = Md5.ComputeHash(Encoding.UTF8.GetBytes(Str1))
16: End Using
17: Dim RespString As String = Convert.ToBase64String(Hash)
18: context.Response.ContentType = "text/plain"
19: context.Response.Write(Left(RespString, Len(RespString) - 4))
20: End If
21: End Sub
22:
23: ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
24: Get
25: Return False
26: End Get
27: End Property
28:
29: End Class
Post-parameters in this case is sending as raw string, like this.
1: Imports System.IO
2: Imports System.Net
3: Imports System.Text
...
9: Dim Html = PostRequest("http://s5.programmer.expert/GetCode.ashx", ID.ToString)
...
26: Public Function PostRequest(Url As String, PostData As String)
27: Dim Html As String
28: Dim ByteArray As Byte() = Encoding.UTF8.GetBytes(PostData)
29: Dim Request As HttpWebRequest = CType(WebRequest.Create(Url), HttpWebRequest)
30: Request.AutomaticDecompression = DecompressionMethods.GZip
31: Request.Method = "POST"
32: Request.ContentType = "application/x-www-form-urlencoded"
33: Request.ContentLength = ByteArray.Length
34: Dim DataStream As Stream = Request.GetRequestStream()
35: DataStream.Write(ByteArray, 0, ByteArray.Length)
36: DataStream.Close()
37: Using Response As HttpWebResponse = CType(Request.GetResponse(), HttpWebResponse)
38: Using Stream As Stream = Response.GetResponseStream()
39: Using Reader As StreamReader = New StreamReader(Stream)
40: Html = Reader.ReadToEnd()
41: End Using
42: End Using
43: End Using
44: Return (Html)
45: End Function
2. WebAPI - modern alternative way to receive complex parameter without model.
Firstly and main point you must understanding - this way not faster, not better, not simple than any old way is listed in previous point - WEbMethod (from Classic ASP.NET), simple WebHandler or independent library like MultipartFormDataParser - this is only a small additional way to doing the same job.
And second point you must understanding - there are some alternative way with using WebAPI to doing the same job to receive complex multipart/form-data parameters. And third main point - this is a way to receive RAW parameters without Model.
And below you may see my first variant of code. This is simplest way to receive multipart/form-data parameters by MultipartFormDataStreamProvider. This class firstly automatically saved uploaded files to TMP directory and after that move files to right place with right name. And as a result it return name of uploaded files.
1: Imports System.Net
2: Imports System.Net.Http
3: Imports System.Web.Http
4:
5: Namespace Controllers
6: Public Class UploadController
7: Inherits ApiController
8:
9: <HttpPost>
10: Public Async Function PostResumeData() As Threading.Tasks.Task(Of HttpResponseMessage)
11:
12: If Request.Content.IsMimeMultipartContent() Then
13: Dim UploadedFileList As List(Of KeyValuePair(Of String, String)) = Await FileDataReader1("~/App_Data/tmp/", "~/App_Data/")
14: End If
15:
16: Dim Response = Request.CreateResponse(HttpStatusCode.Moved)
17: Response.Headers.Location = New Uri("http://localhost:54598/Project/Search") 'Return RedirectToAction("Search", "Project")
18: Return Response
19:
20: End Function
21:
22: Async Function FileDataReader1(TmpRoot As String, UserRoot As String) As Threading.Tasks.Task(Of List(Of KeyValuePair(Of String, String)))
23:
24: Dim TmpRootDir As String = HttpContext.Current.Server.MapPath(TmpRoot)
25: Dim StreamProvider = New System.Net.Http.MultipartFormDataStreamProvider(TmpRootDir)
26: Dim RDR = Await Request.Content.ReadAsMultipartAsync(StreamProvider)
27:
28: Dim UploadedFileList = New List(Of KeyValuePair(Of String, String))
29:
30: Try
31: For Each FileData As Net.Http.MultipartFileData In StreamProvider.FileData
32:
33: If Not String.IsNullOrWhiteSpace(FileData.Headers.ContentDisposition.FileName) Then
34: 'Uploading file
35: Dim FileName = FileData.Headers.ContentDisposition.FileName.Replace("""", "")
36: If Not String.IsNullOrWhiteSpace(FileName) Then
37: Dim UserFileName As String = IO.Path.Combine(HttpContext.Current.Server.MapPath(UserRoot), FileName)
38: IO.File.Move(FileData.LocalFileName, UserFileName)
39: Dim Key1 = FileData.Headers.ContentDisposition.Name.Replace("""", "")
40: UploadedFileList.Add(New KeyValuePair(Of String, String)(Key1, FileName))
41: End If
42: End If
43: Next
44:
45: Return UploadedFileList
46:
47: Catch e As System.Exception
48: Throw New Web.Http.HttpResponseException(e.Message)
49: End Try
50:
51: End Function
52:
53: End Class
54: End Namespace
The second variant of code is more interesting, It still based on task-based programming model wait Async/Await, still parse parameters from the same form. but instead complex class MultipartFormDataStreamProvider is parse directly input content by StreamReader. Therefore additionally to upload files this variant of code is receive simple parameters from form, not only uploaded files.
Also this way give opportunity to receive not only one string parameters, but directly all receiving data to NameValueCollection.
17: Dim FormValues As List(Of KeyValuePair(Of String, String)) = Await FileDataReader2(AddressOf MyFileProcessor)
57:
58: Async Function FileDataReader2(ByVal FileProcessor As Action(Of String, IO.Stream)) As Threading.Tasks.Task(Of List(Of KeyValuePair(Of String, String)))
59:
60: Dim StreamContent = New Http.StreamContent(HttpContext.Current.Request.InputStream)
61: StreamContent.Headers.ContentType = Net.Http.Headers.MediaTypeHeaderValue.Parse(HttpContext.Current.Request.ContentType)
62: Dim StreamProvider = Await StreamContent.ReadAsMultipartAsync()
63:
64: Dim FormValues = New List(Of KeyValuePair(Of String, String))
65:
66: Try
67: For Each HttpContent In StreamProvider.Contents
68:
69: If Not String.IsNullOrWhiteSpace(HttpContent.Headers.ContentDisposition.FileName) Then
70: Dim FileName = HttpContent.Headers.ContentDisposition.FileName.Replace("""", "")
71: If Not String.IsNullOrWhiteSpace(FileName) Then
72: 'Uploading file
73: Using FileContents As IO.Stream = Await HttpContent.ReadAsStreamAsync()
74: FileProcessor(FileName, FileContents)
75: End Using
76: Dim Key1 = HttpContent.Headers.ContentDisposition.Name.Replace("""", "")
77: FormValues.Add(New KeyValuePair(Of String, String)(Key1, FileName))
78: End If
79: Else
80: 'simple value
81: Dim Val1 = Await HttpContent.ReadAsStringAsync
82: Dim Key1 = HttpContent.Headers.ContentDisposition.Name.Replace("""", "")
83: FormValues.Add(New KeyValuePair(Of String, String)(Key1, Val1))
84: End If
85: Next
86:
87: Return FormValues
88:
89: Catch ex As Exception
90: Throw New Web.Http.HttpResponseException(ex.Message)
91: End Try
92:
93: End Function
94:
95: Private Function MyFileProcessor(FileName As String, FileContents As IO.Stream)
96: Dim UserRootDir As String = HttpContext.Current.Server.MapPath("~/App_Data/")
97: Dim ResFileName As String = IO.Path.Combine(UserRootDir, FileName)
98: Using FS = New IO.FileStream(ResFileName, IO.FileMode.Create, IO.FileAccess.Write, IO.FileShare.None)
99: FileContents.CopyToAsync(FS)
100: End Using
101: Return ResFileName
102: End Function
There are one small differences to use directly WebHandler and WebApi, so far as WebApi is processed by IIS Route, we must tune RouteConfig class.
1: Imports System
2: Imports System.Collections.Generic
3: Imports System.Linq
4: Imports System.Web
5: Imports System.Web.Mvc
6: Imports System.Web.Routing
7:
8: Public Module RouteConfig
9: Public Sub RegisterRoutes(ByVal routes As RouteCollection)
10: routes.IgnoreRoute("{resource}.axd/{*pathInfo}")
11:
12: routes.MapRoute(
13: name:="Default",
14: url:="{controller}/{action}/{id}",
15: defaults:=New With {.controller = "Home", .action = "Index", .id = UrlParameter.Optional}
16: )
17: End Sub
18: End Module
3. Receive data in MVC controller without model (by FormCollection or by Name).
The first way to receive simple parameters without model is using FormCollection class. There are some example in my site with this method.
- ???????????????? ???????? ???????????????? ???????????????? ???????????????? (first project).
- ???????????????????? ?????????????????????? ???????????? ?????? ?????????? ????????????.
- ?????????????? ?????? ?????????????????? ?????? ?? ???????????????? MVC.
- ?????????? ???????????? ?????????????????????? ???????????????????? ???? ASP NET MVC.
The second way to receive simple paramers without model is using name of parameters exactly as it named in View (for example - UserID as string, Password as string). Advantage of this type to receive parameters is automatically type casting. This is template of new MVC code controller created by Visual Studio.
Example of this approach you may see in end of page:
4. Receive data in MVC with model.
A good example of receive simple parameters with model you can see in page StudentsController2.vb (Contoso University). If you create controller by scafford template, you can see all of class of your project and you can select class for template for Model what using to thansfer data between view and controller.
But this is extremally simple example. Go ahead to real code.
Firstly, if you using model no sense take simple html-tag in form like <label> or <input>. All MVC concept is buitling across various attributes like Data Annotations, Validation Atributes and other. Therefore first point to take advantage for this way to transfer data between controller and view is creation Model and second point is using special ASP.NET tag in View, like @Html.TextAreaFor and @Html.ValidationMessageFor, which automatically process this attributes for various purposes
Because I use in my project Model first concept, I have no right directly add needed attributes in DB definition (at common this is standard MVVM concept).
Therefore I prepare additional View model with needed attributes.
1: Imports System.ComponentModel.DataAnnotations
2:
3: Public Class ViewResumeModel
4:
5: <Required(ErrorMessage:="Skills is mandatory.")>
6: <StringLength(1000)>
7: Public Property Skills As String
8:
9: <Required(ErrorMessage:="Title is mandatory.")>
10: <Display(Name:="Title of your bean", Prompt:="Title of your bean", Description:="No more than 100 chars")>
11: <StringLength(100)>
12: Public Property Title As String
13:
14: <DataType(DataType.Upload)>
15: <Display(Name:="Upload PDF files with your resume (if necessary)")>
16: Public Property InputPDFFile As HttpPostedFileBase
17:
18: <DataType(DataType.Upload)>
19: <Display(Name:="Upload your Avatar (if necessary)")>
20: Public Property InputAvaFile As HttpPostedFileBase
21:
22: <Required(ErrorMessage:="Description is mandatory.")>
23: <Display(Name:="Enter description for customer.", Prompt:="Enter description for customer.", Description:="No more than 1000 chars.")>
24: <DataType(DataType.MultilineText)>
25: <StringLength(1000)>
26: Public Property ShortDescription As String
27:
28: <Required(ErrorMessage:="PublicContacts is mandatory.")>
29: <Display(Name:="Enter your public contacts for customer.", Prompt:="Enter your public contacts for customer.", Description:="Any your public contact in free form, No more than 100 chars.")>
30: <DataType(DataType.Text)>
31: <StringLength(100)>
32: Public Property PublicContacts As String
33:
34: <Display(Name:="Enter your email for Sign in to this site.", Prompt:="Enter your email for Sign in to this site.", Description:="We sent password to this email.")>
35: <DataType(DataType.EmailAddress)>
36: Public Property AdminContacts As String
37:
38: End Class
And change the view for this model:
1: @ModelType ViewResumeModel
8:
9: <div class="row">
10: @*<form role="form" name="resumeform" id="resumeform" method="post" enctype="multipart/form-data" action="/api/Upload/PostResumeData">*@
11: @Using (Html.BeginForm("PostResume", "Resume", FormMethod.Post, New With {.enctype = "multipart/form-data"}))
12: @Html.AntiForgeryToken()
13: @<div Class="col-md-1 panel1" style="border:none">
14: </div>
15: @Html.Partial("~/Views/Resume/PostSetSkillPanel.vbhtml")
16: @<div class="col-md-7 panel1">
17: <h2> Please fill all fields in your public resume </h2>
18: <div style="max-height: 750px; min-height:750px; overflow: auto;">
19: <div class="form-group">
20: @*<label for="Title"><span style="color:red">*</span> Title of your bean </label>
21: <input class="form-control" id="title" name="title" placeholder="No more than 100 chars.">*@
22: @Html.LabelFor(Function(m) m.Title)
23: @Html.ValidationMessageFor(Function(m) m.Title, "", New With {.style = "color:red"})
24: @Html.TextBoxFor(Function(m) m.Title, New With {.PlaceHolder = "No more than 100 chars.", .Style = "width:95%;"})
25: </div>
26: <div Class="form-group">
27: @*<label for="InputPDFFile">Upload PDF files with your resume</label>
28: <input type="file" class="form-control-file" id="InputPDFFile" name="InputPDFFile">*@
29: @Html.LabelFor(Function(m) m.InputPDFFile)
30: @Html.TextBoxFor(Function(m) m.InputPDFFile, New With {.type = "file", .Style = "width:95%;"})
31: <p class="help-block">This pdf files not will be parsed or changed.</p>
32: </div>
33: <div class="form-group">
34: @*<label for="InputAvaFile">Upload your Avatar (if necessary)</label>
35: <input type="file" class="form-control-file" id="InputAvaFile" name="InputAvaFile">*@
36: @Html.LabelFor(Function(m) m.InputAvaFile)
37: @Html.TextBoxFor(Function(m) m.InputAvaFile, New With {.type = "file", .Style = "width:95%;"})
38: <p class="help-block">Will be reduced to 100x100 px</p>
39: </div>
40: <div class="form-group">
41: @*<label for="ShortDescription"><span style="color:red">*</span> Enter description for customer </label>
42: <textarea class="form-control" id="ShortDescription" rows="7" placeholder="No more than 1000 chars." name="ShortDescription"></textarea>*@
43: @Html.LabelFor(Function(m) m.ShortDescription)
44: @Html.ValidationMessageFor(Function(m) m.ShortDescription, "", New With {.style = "color:red"})
45: @Html.TextAreaFor(Function(m) m.ShortDescription, New With {.rows = "7", .PlaceHolder = "No more than 1000 chars.", .Style = "width:95%;"})
46: </div>
47: <div class="form-group">
48: @*<label for="PublicContacts"><span style="color:red">*</span> Enter your public contacts for customer </label>
49: <input class="form-control" id="PublicContacts" placeholder="Any your public contact in free form, No more than 100 chars." name="PublicContacts">*@
50: @Html.LabelFor(Function(m) m.PublicContacts)
51: @Html.ValidationMessageFor(Function(m) m.PublicContacts, "", New With {.style = "color:red"})
52: @Html.TextBoxFor(Function(m) m.PublicContacts, New With {.PlaceHolder = "Any your public contact in free form, No more than 100 chars.", .Style = "width:95%;"})
53: </div>
54: <div class="form-group">
55: @*<label for="AdminContacts">Enter your email for Sign in to this site. </label>
56: <input type="email" class="form-control" id="AdminContacts" placeholder="We sent password to this email." name="AdminContacts">*@
57: @Html.LabelFor(Function(m) m.AdminContacts)
58: @Html.ValidationMessageFor(Function(m) m.AdminContacts, "", New With {.style = "color:red"})
59: @Html.TextBoxFor(Function(m) m.AdminContacts, New With {.PlaceHolder = "We sent password to this email.", .Style = "width:200px;"})
60: <span style="color:red">*</span> or <br />
61: <label for="Publiccontacts">Sign In using another account</label>
62: <a class="oauth" alt="Sign in using Github" title="Sign in using Github" href="/script/Membership/OAuthLogOn.aspx?auth=GitHub"><img src="/Images/octicons_github-lg.png" style="vertical-align:middle;padding-right:3px;border:0;"></a>
63: <a class="oauth" alt="Sign in using Linkedin" title="Sign in using Linkedin" href="/script/Membership/OAuthLogOn.aspx?auth=LinkedIn"><img src="/Images/linkedin-lg.png" style="vertical-align:middle;padding-right:3px;border:0;"></a>
64: <a class="oauth" alt="Sign in using Facebook" title="Sign in using Facebook" href="/script/Membership/OAuthLogOn.aspx?auth=Facebook"><img src="/Images/facebook-lg.png" style="vertical-align:middle;padding-right:3px;border:0;"></a>
65: <a class="oauth" alt="Sign in using Google" title="Sign in using Google" href="/script/Membership/OAuthLogOn.aspx?auth=Google"><img src="/Images/google-plus-lg.png" style="vertical-align:middle;padding-right:3px;border:0;"></a>
66: <a class="oauth" alt="Sign in using Microsoft" title="Sign in using Microsoft" href="/script/Membership/OAuthLogOn.aspx?auth=Microsoft"><img src="/Images/microsoft-lg.png" style="vertical-align:middle;padding-right:3px;border:0;"></a>
67: </div>
68: <button id="PostResume" name="PostResume" type="submit" class="btn btn-primary">Post Resume</button>
69: @Html.ValidationSummary(True, "", New With {.style = "color:red"})
70: <div style="color:red">@ViewBag.Errormessage</div>
71: </div>
72: </div>
73: End Using
74: @*</form>*@
75: </div>
76:
77: <script src="~/Scripts/jquery.validate.min.js"></script>
78: <script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
And after that I have succesfully receive model in MVC comtroller:
5. Custom model provider.
If we have more complex model (you need calculation fields for example or filter it or other prepare) we can opportunity to create own model from simple form fields. Firstly we need prepare special model you need for. In this example I prepare model with name ViewResumeModel2 that has only one difference to model above - instead string in field "skills" it transfer filtered list of string.
Of cource, need to change type of model in controller and view.
My code of special custom model binder is look these.
1: Public Class ??ustomModelBinder
2: Inherits DefaultModelBinder
3:
4: Public Overrides Function BindModel(controllerContext As ControllerContext, bindingContext As ModelBindingContext) As Object
5: Select Case bindingContext.ModelType
6: Case GetType(ViewResumeModel2)
7: Dim Request As HttpRequestBase = controllerContext.HttpContext.Request
8: Dim SkillArr() As String = Request.Form("skills").Split(":")
9: Return New ViewResumeModel2 With {
10: .Title = Request.Form("Title"),
11: .ShortDescription = Request.Form("ShortDescription"),
12: .PublicContacts = Request.Form("PublicContacts"),
13: .AdminContacts = Request.Form("AdminContacts"),
14: .InputAvaFile = Request.Files("InputAvaFile"),
15: .InputPDFFile = Request.Files("InputPDFFile"),
16: .Skills = (SkillArr.ToList.Where(Function(x) Not String.IsNullOrEmpty(x))).ToList
17: }
18: Case Else
19: Return MyBase.BindModel(controllerContext, bindingContext)
20: End Select
21: End Function
22:
23: End Class
And in the last step we need to register our custom model bulder on start site procedures.
And this schema working perfectly:
6. Define parameters as raw stream.
Than application/x-www-form-urlencoded stream can be read by the way in line 177 and parsed by the way in line 182.
170: Public Async Function CreateDriver(Stream As Stream) As Task(Of Contract.Driver) Implements IDriverService.CreateDriver
172:
173: If Stream Is Nothing Then
174: Throw New WebFaultException(Of String)("MISSING_PARAMETERS", HttpStatusCode.BadRequest)
175: End If
176:
177: Dim Body As String = New StreamReader(Stream).ReadToEnd()
178: If String.IsNullOrWhiteSpace(Body) Then
179: Throw New WebFaultException(Of String)("MISSING_PARAMETERS", HttpStatusCode.BadRequest)
180: End If
181:
182: Dim Form As NameValueCollection = HttpUtility.ParseQueryString(Body)
Stream also can contains Image or another byte/stream, in this case this is a simplest way to handle it.
367: Public Async Function CreateDriverImage(DriverIdPart As String, Stream As Stream) As Task(Of Contract.File) Implements IDriverService.CreateDriverImage
368: 'Await Federate(Reflection.MethodBase.GetCurrentMethod().Name)
...:
392: LocalStorage.WriteFileToDataStore(Root, Location, Stream)
7. Get/Post request to controller from Javascript.
This is controller code.
And this is example of Javascript to create Get/Post request to controller. Script can be attach when form-ready to as @Ajax.BeginForm.
1: var did = null;
2: var dob = null;
3:
4: function OnUpdateDriverBegin(xhr)
5: {
6: var textId = $('#input-driver-id');
7: var textFirstName = $('#input-driver-first-name');
8: var textLastName = $('#input-driver-last-name');
9: var textEmail = $('#input-driver-email');
10: var textPhone = $('#input-driver-phone');
11: var dropdownStatus = $('#input-driver-status');
12:
13: var labelStatusMessage = $('#status-message');
14: labelStatusMessage.empty();
15:
16: var id = textId.val().trim();
17:
18: var firstName = textFirstName.val().trim();
19: if (firstName === null || firstName.length <= 0)
20: {
21: labelStatusMessage.text("Please enter First Name");
22: return false;
23: }
24:
25: var lastName = textLastName.val().trim();
26: if (lastName === null || lastName.length <= 0)
27: {
28: labelStatusMessage.text("Please enter Last Name");
29: return false;
30: }
31:
32: var email = textEmail.val().trim();
33: if (email === null || email.length <= 0)
34: {
35: labelStatusMessage.text("Please enter Email");
36: return false;
37: }
38:
39: var emailRegex = /^([a-zA-Z0-9_.+-])+\@(([a-zA-Z0-9-])+\.)+([a-zA-Z0-9]{2,4})+$/;
40: if (!emailRegex.test(email))
41: {
42: labelStatusMessage.text("Please enter valid Email");
43: return false;
44: }
45:
46: var phone = textPhone.val().trim();
47: if (phone === null || phone.length <= 0)
48: {
49: labelStatusMessage.text("Please enter Phone");
50: return false;
51: }
52:
53: //if (phone.indexOf("+972") !== 0)
54: //{
55: // labelStatusMessage.text("Please enter valid Phone");
56: // return false;
57: //}
58:
59: var contentPanel = $('#content-panel');
60: var progressPanel = $('#progress-panel');
61:
62: contentPanel.hide();
63: progressPanel.show();
64: return true;
65: }
66:
67: function OnUpdateDriverSuccess(data, status, xhr)
68: {
69: var labelStatusMessage = $('#status-message');
70: labelStatusMessage.empty();
71:
72: if (xhr.status === 200)
73: {
74: window.location.href = "/Driver";
75: }
76: else
77: {
78: labelStatusMessage.text("A temporary error occured");
79: }
80: }
81:
82: function OnUpdateDriverFailure(xhr, status, error)
83: {
84: var contentPanel = $('#content-panel');
85: var progressPanel = $('#progress-panel');
86:
87: contentPanel.show();
88: progressPanel.hide();
89:
90: var labelStatusMessage = $('#status-message');
91: switch (xhr.status)
92: {
93: case 400:
94: labelStatusMessage.text("Missing or invalid User Details");
95: break;
96:
97: case 403:
98: window.location.href = "/";
99: break;
100:
101: case 500:
102: default:
103: labelStatusMessage.text("A temporary error occured");
104: break;
105: }
106: }
107:
108: function DeleteDriver()
109: {
110: var contentPanel = $('#content-panel');
111: var progressPanel = $('#progress-panel');
112:
113: contentPanel.hide();
114: progressPanel.show();
115:
116: var serviceUrl = '/Service/Driver/Delete/' + did;
117:
118: $.ajax({
119: url: serviceUrl,
120: type: 'DELETE',
121: async: true,
122: cache: false,
123: contentType: false,
124: processData: false,
125: success: function (data, status, xhr)
126: {
127: var labelStatusMessage = $('#status-message');
128: labelStatusMessage.empty();
129:
130: if (xhr.status === 200)
131: {
132: window.location.href = "/Driver";
133: }
134: else
135: {
136: labelStatusMessage.text("A temporary error occured");
137: }
138: },
139: error: function (jqXHR, textStatus, errorThrown)
140: {
141: progressPanel.hide();
142: contentPanel.show();
143: switch (jqXHR.status)
144: {
145: case 403:
146: window.location.href = "/";
147: break;
148:
149: default:
150: $.notify({ message: jqXHR.responseJSON }, { type: 'danger', timer: 2000 });
151: break;
152: }
153: }
154: });
155: }
156:
157: function loadRideTypes()
158: {
159: var contentPanel = $('#content-panel');
160: var progressPanel = $('#progress-panel');
161:
162: //contentPanel.hide();
163: //progressPanel.show();
164:
165: var serviceUrl = '/Service/RideType';
166:
167: $.ajax({
168: url: serviceUrl,
169: type: 'GET',
170: async: true,
171: cache: false,
172: contentType: false,
173: processData: false,
174: success: function (returnedData)
175: {
176: var rideTypesJson = returnedData;
177:
178: var dropdownCarRideType = $('#input-car-ride-type');
179:
180: var textFirstName = $('#input-driver-first-name');
181: var textCarManufacturer = $('#input-car-manufacturer');
182:
183: var htmlString = "";
184: htmlString = htmlString + '<option value="-1" selected="selected">Select Ride Type</option>';
185: for (var rideTypeIndex in returnedData)
186: {
187: var rideTypeJson = rideTypesJson[rideTypeIndex];
188: var rideTypeId = rideTypeJson['Id'];
189: var rideTypeEName = rideTypeJson['EName'];
190: var rideTypeHName = rideTypeJson['HName'];
191: htmlString += '<option value="' + rideTypeId + '">' + rideTypeHName + '</option>';
192: }
193: dropdownCarRideType.html(htmlString);
194:
195: var hasCar = dob['HasCar'];
196: var carJson = dob['Car'];
197:
198: if (hasCar && carJson)
199: {
200: var carRideType = carJson['RideTypeId'];
201: dropdownCarRideType.val(carRideType);
202: }
203:
204: progressPanel.hide();
205: contentPanel.show();
206:
207: $(".btn-view-driver-document").click(ViewDriverDocument);
208: $(".btn-verify-driver-document").click(VerifyDriverDocument);
209:
210: textFirstName.focus();
211: textCarManufacturer.focus();
212: },
213: error: function (jqXHR, textStatus, errorThrown)
214: {
215: progressPanel.hide();
216: contentPanel.show();
217: switch (jqXHR.status)
218: {
219: case 403:
220: window.location.href = "/";
221: break;
222:
223: default:
224: $.notify({ message: jqXHR.responseJSON }, { type: 'danger', timer: 2000 });
225: break;
226: }
227: }
228: });
229: }
230:
231: function VerifyDriverDocument(e)
232: {
233: e.currentTarget.innerHTML = '<i class="fa fa-check"></i> Verifying..';
234: $(e.currentTarget).prop('disabled', true);
235:
236: var serviceUrl = '/Service/Driver/Document/Verify';
237:
238: $.ajax({
239: url: serviceUrl,
240: type: 'POST',
241: async: true,
242: cache: false,
243: contentType: false,
244: data: $.param({ DocumentIdPart: String(e.currentTarget.id).replace('btn', '') }),
245: headers: {
246: 'Content-Type': 'application/x-www-form-urlencoded'
247: },
248: processData: false,
249: success: function (data, status, xhr)
250: {
251: if (xhr.status === 200)
252: {
253: e.currentTarget.innerHTML = '<i class="fa fa-check"></i> Verified';
254: $(e.currentTarget).prop('disabled', true);
255: }
256: else
257: {
258: e.currentTarget.innerHTML = '<i class="fa fa-check"></i> Verify';
259: $(e.currentTarget).prop('disabled', false);
260: $.notify({ message: jqXHR.responseJSON }, { type: 'danger', timer: 2000 });
261: }
262: },
263: error: function (jqXHR, textStatus, errorThrown)
264: {
265: switch (jqXHR.status)
266: {
267: default:
268: e.currentTarget.innerHTML = '<i class="fa fa-check"></i> Verify';
269: $(e.currentTarget).prop('disabled', false);
270: $.notify({ message: jqXHR.responseJSON }, { type: 'danger', timer: 2000 });
271: break;
272: }
273: }
274: });
275: }
276:
277: function ViewDriverDocument(e)
278: {
279: //e.stopPropagation();
280: //e.stopImmediatePropagation();
281: var documentFileId = String(e.currentTarget.id).replace('btn', '');
282: var win = window.open('http://api.taxistar.co.il/CoreService.svc/File/' + documentFileId);
283: if (win)
284: {
285: //Browser has allowed it to be opened
286: win.focus();
287: }
288: else
289: {
290: //Browser has blocked it
291: alert('Please allow popups for this website');
292: }
293: }
294:
295: function loadDriver()
296: {
297: var contentPanel = $('#content-panel');
298: var progressPanel = $('#progress-panel');
299:
300: contentPanel.hide();
301: progressPanel.show();
302:
303: var serviceUrl = '/Service/User/View/' + did;
304:
305: $.ajax({
306: url: serviceUrl,
307: type: 'GET',
308: async: true,
309: cache: false,
310: contentType: false,
311: processData: false,
312: success: function (returnedData)
313: {
314: var userJson = returnedData;
315:
316: // driver details
317: var textId = $('#input-driver-id');
318: var imageDriver = $('#input-driver-profile-image');
319: var textFirstName = $('#input-driver-first-name');
320: var textLastName = $('#input-driver-last-name');
321: var textEmail = $('#input-driver-email');
322: var textPhone = $('#input-driver-phone');
323: var dropdownStatus = $('#input-driver-status');
324:
325: // car details
326: var dropdownCarType = $('#input-car-type');
327: var textCarManufacturer = $('#input-car-manufacturer');
328: var textCarModel = $('#input-car-model');
329: var textCarCapacity = $('#input-car-capacity');
330: var textCarColor = $('#input-car-color');
331: var textCarRegistration = $('#input-car-registration');
332:
333: var id = userJson['Id'];
334: textId.val(id);
335:
336: var firstName = userJson['FirstName'];
337: textFirstName.val(firstName);
338:
339: var lastName = userJson['LastName'];
340: textLastName.val(lastName);
341:
342: var status = userJson['Status'];
343: dropdownStatus.val(status);
344:
345: var contactsJson = userJson['Contacts'];
346:
347: var email = null;
348: var phone = null;
349:
350: for (var contactIndex in contactsJson)
351: {
352: var contactJson = contactsJson[contactIndex];
353: if (contactJson['Type'] == 1)
354: {
355: phone = contactJson;
356: }
357: else if (contactJson['Type'] == 2)
358: {
359: email = contactJson;
360: }
361: }
362:
363: var email = email['Value'];
364: textEmail.val(email);
365:
366: var phone = phone['Value'];
367: textPhone.val(phone);
368:
369: var driverProfile = userJson['Profile'];
370: if (driverProfile)
371: {
372: var driverProfileThumbnail = driverProfile['Thumbnail'];
373: if (driverProfileThumbnail)
374: {
375: imageDriver.attr("src", "http://api.taxistar.co.il/CoreService.svc/File/" + driverProfileThumbnail['Id']);
376: }
377: }
378:
379: var hasCar = userJson['HasCar'];
380: var carJson = userJson['Car'];
381:
382: if (hasCar && carJson)
383: {
384: var carManufacturer = carJson['Manufacturer'];
385: textCarManufacturer.val(carManufacturer);
386:
387: var carModel = carJson['Model'];
388: textCarModel.val(carModel);
389:
390: var carCapacity = carJson['Capacity'];
391: textCarCapacity.val(carCapacity);
392:
393: var carColor = carJson['Color'];
394: textCarColor.val(carColor);
395:
396: var carRegistration = carJson['RegistrationNumber'];
397: textCarRegistration.val(carRegistration);
398:
399: var carType = carJson['Type'];
400: dropdownCarType.val(carType);
401: }
402:
403: var documentsJson = userJson['Documents'];
404:
405: var htmlString = "";
406: for (var documentIndex in documentsJson)
407: {
408: var documentJson = documentsJson[documentIndex];
409:
410: var documentId = documentJson['Id'];
411:
412: var documentType = '';
413: switch (documentJson['Type'])
414: {
415: case 1:
416: documentType = "Driver Licence";
417: break;
418:
419: case 2:
420: documentType = "Car Licence";
421: break;
422:
423: case 3:
424: documentType = "Car Insurance";
425: break;
426:
427: case 4:
428: documentType = "Taxi Licence";
429: break;
430: }
431:
432: var documentIdentifier = documentJson['Identifier'];
433: var validFrom = documentJson['ValidityFrom'];
434: var validTo = documentJson['ValidityTo'];
435: var isVerified = documentJson['IsVerified'];
436: var documentFileId = documentJson['File']['Id'];
437:
438: //var verified = '';
439: //if (isVerified)
440: // verified = "Yes";
441: //else
442: // verified = "No";
443:
444: htmlString += '<tr><td>' + documentType + '</td><td>' + documentIdentifier + '</td><td>' + validFrom + '</td><td>' + validTo + '</td>';
445:
446: htmlString += '<td><button type="button" class="btn btn-danger btn-round btn-view-driver-document" role="button" id="btn' + documentFileId + '"><i class="fa fa-eye"></i> View</button></td>';
447:
448: if (isVerified)
449: htmlString += '<td><button type="button" class="btn btn-danger btn-round btn-verify-driver-document" role="button" id="btn' + documentId + '" disabled="disabled"><i class="fa fa-check"></i> Verified</button></td>';
450: else
451: htmlString += '<td><button type="button" class="btn btn-danger btn-round btn-verify-driver-document" role="button" id="btn' + documentId + '"><i class="fa fa-check"></i> Verify</button></td>';
452:
453: htmlString += '</tr>';
454: }
455:
456: var tableBodyDocuments = $('#table-body-documents');
457: tableBodyDocuments.html(htmlString);
458:
459: dob = userJson;
460:
461: //progressPanel.hide();
462: //contentPanel.show();
463:
464: //textFirstName.focus();
465: //textCarManufacturer.focus();
466:
467: loadRideTypes();
468: },
469: error: function (jqXHR, textStatus, errorThrown)
470: {
471: progressPanel.hide();
472: contentPanel.show();
473: switch (jqXHR.status)
474: {
475: case 403:
476: window.location.href = "/";
477: break;
478:
479: default:
480: $.notify({ message: jqXHR.responseJSON }, { type: 'danger', timer: 2000 });
481: break;
482: }
483: }
484: });
485: }
486:
487: function documentReady()
488: {
489: var parts = window.location.href.split('/');
490: var lastSegment = parts.pop() || parts.pop();
491: did = lastSegment;
492:
493: var buttonDelete = $('#button-driver-delete-submit');
494: if (buttonDelete !== null)
495: buttonDelete.click(DeleteDriver);
496:
497: loadDriver();
498: }
499:
500: $(document).ready(documentReady);
More of this method Inject OnBegin/OnSuccess/OnFailure custom Javascript code into ASP.NET Ajax tag by Bundle of jquery.unobtrusive-ajax.min.js
|