Development Environment
Dell Laptop
.Net Framework 3.5 SP1
Visual Studio.Net 2008 SP1 (Team System Developer, Tester, Database)
Silverlight 3.0
Fiddler 2
SQL Server Management Studio 2008 SP1
Alpha/Dev Web Server
Windows Server 2003 Standard Edition SP2
IIS v 6.0
Alpha/Dev SQL Server 2005 - databases (2) are 2000 compatible library
Existing Production Application
“Transcript Currier”
ASP.NET 2.0 (VB) Web Application
SQL Server 2000
The existing system:
User Type: Customer
1.
"Login" Page - customer logs in
2.
"Jobs List" Page - customer chooses a job or creates a
new one
3.
"Customer Upload" page
a.
Fill out the basic job information
b.
Identify the number of transcripts within the job
(GridView Control)
i.
Transcript Header (auto-generated <JobNumber>An)
ii.
Case Number, Description, Copies (user input)
c.
Pick a transcript header (dropdown control) and
associate a file (file upload control) - 10 static control sets
d.
Process the Job (click button control)
i.
validation run
1.
required fields
2.
valid business dates
3.
check file type (usually audio)
ii.
moves the files to File Server via virtual directory on
Web Server IIS Site
iii.
compresses files into a <project code directory>/<job
number directory>\<job number>.zip file
iv.
processes the job details in database posting compressed
file path for transcriptionists to pick up work
The desire is to modify the existing application to
1.
replace 10 static control sets with one control set
(transcription header dropdown and file picker)
2.
allow the user to select multiple files from various
location
3.
present a list of properly associated files <job number>
<transcript header> and <files>
4.
compress files or
take a compressed file <job number>.zip {<transcript header directory>\<fiels>}
5.
transfer compressed file to the File Server via virtual
directory on Web Server IIS site (as is done now)
The Silverlight User Control as I have it outlined now is a replacement for the
static dropdown/file upload control set and contains a ComboBox, a filepicker,
two textblocks, and a button.
·
ComboBox – select the transcript header
aka CaseFileName
·
FilePicker – choose the file(s) from your machine
(may be done repeatedly)
·
TextBlock1 – display the files picked
·
TextBlock2 – display the files existing/selected
for the transcript
·
Button – Upload the files
In the current outlined work flow, when the user is done they’ll process the job
details
I’ve got four issues when I actually tie the tools together at this moment.
- Silverlight ComboBox does not populate
- Silverlight intermittently spits up
cross-domain policy soap errors - Silverlight upload file(s) – splits file(s) into small
packages and moves to the file server – appears to be spawning multiple threads
resulting in file write conflict errors - The UI looks atrociously worse than it did before – which is
saying a lot.
So as always, I’ve decoupled the scenarios to try to get to the base issues.
- Silverlight ComboBox does not populate
http://10.1.251.62/ys2005web/TestSilverlightControl1.aspx
http://10.1.251.62/ys2005web/SlC1WebService.asmx
SlC1WebService
Click here for a complete list of operations.
GetTranscriptHeaderRecords
Test
The test form is only available for requests from the local machine.
SOAP 1.1
The following is a sample SOAP 1.1 request and response. The placeholders shown need to be replaced with actual values.
POST /ys2005web/SlC1WebService.asmx HTTP/1.1 Host: 10.1.251.62 Content-Type: text/xml; charset=utf-8 Content-Length: length SOAPAction: "http://10.1.251.62/ys2005web/GetTranscriptHeaderRecords" <?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <GetTranscriptHeaderRecords xmlns="http://10.1.251.62/ys2005web/"> <jobNumber>int</jobNumber> </GetTranscriptHeaderRecords> </soap:Body> </soap:Envelope>
HTTP/1.1 200 OK Content-Type: text/xml; charset=utf-8 Content-Length: length <?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <GetTranscriptHeaderRecordsResponse xmlns="http://10.1.251.62/ys2005web/"> <GetTranscriptHeaderRecordsResult> <vwTranscriptHeaderRecords> <CaseNo>string</CaseNo> <Copies>string</Copies> <Description>string</Description> <Dumped>boolean</Dumped> <Filename>string</Filename> <JobNumber>int</JobNumber> </vwTranscriptHeaderRecords> <vwTranscriptHeaderRecords> <CaseNo>string</CaseNo> <Copies>string</Copies> <Description>string</Description> <Dumped>boolean</Dumped> <Filename>string</Filename> <JobNumber>int</JobNumber> </vwTranscriptHeaderRecords> </GetTranscriptHeaderRecordsResult> </GetTranscriptHeaderRecordsResponse> </soap:Body> </soap:Envelope>
SOAP 1.2
The following is a sample SOAP 1.2 request and response. The placeholders shown need to be replaced with actual values.
POST /ys2005web/SlC1WebService.asmx HTTP/1.1 Host: 10.1.251.62 Content-Type: application/soap+xml; charset=utf-8 Content-Length: length <?xml version="1.0" encoding="utf-8"?> <soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope"> <soap12:Body> <GetTranscriptHeaderRecords xmlns="http://10.1.251.62/ys2005web/"> <jobNumber>int</jobNumber> </GetTranscriptHeaderRecords> </soap12:Body> </soap12:Envelope>
HTTP/1.1 200 OK Content-Type: application/soap+xml; charset=utf-8 Content-Length: length <?xml version="1.0" encoding="utf-8"?> <soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope"> <soap12:Body> <GetTranscriptHeaderRecordsResponse xmlns="http://10.1.251.62/ys2005web/"> <GetTranscriptHeaderRecordsResult> <vwTranscriptHeaderRecords> <CaseNo>string</CaseNo> <Copies>string</Copies> <Description>string</Description> <Dumped>boolean</Dumped> <Filename>string</Filename> <JobNumber>int</JobNumber> </vwTranscriptHeaderRecords> <vwTranscriptHeaderRecords> <CaseNo>string</CaseNo> <Copies>string</Copies> <Description>string</Description> <Dumped>boolean</Dumped> <Filename>string</Filename> <JobNumber>int</JobNumber> </vwTranscriptHeaderRecords> </GetTranscriptHeaderRecordsResult> </GetTranscriptHeaderRecordsResponse> </soap12:Body> </soap12:Envelope>
B. The Silverlight Control
Imports
System.Diagnostics
Imports
System.Windows.Browser
Partial
Public Class
SilverlightControl1
Inherits UserControl
Public Sub
New()
InitializeComponent()
End Sub
Public Sub
New(ByVal
JobNumber As String)
InitializeComponent()
cboTranscriptHeader_Load(JobNumber)
End Sub
'
-------------------------------------------------------------------------------------
#Region
"** event handling"
Protected Sub
cboTranscriptHeader_ItemSelected( _
ByVal sender As
Object, _
ByVal e As
SelectionChangedEventArgs) Handles
cboTranscriptHeader.SelectionChanged
Debug.Assert(sender IsNot
Nothing, "sender is
null.")
Debug.Assert(e IsNot
Nothing, "e is null.")
If cboTranscriptHeader.SelectedItem
Is Nothing
Then
Return
End If
'Note: "Transcript Header Id"
(WebDumper.dbo.CustomerUploadFiles.CaseFileName)
Dim TranscriptHeader As
String =
Convert.ToString(cboTranscriptHeader.SelectedItem)
'ToDo: Code required when a Transcript Header Id is
selected
' A
specific Customer Job have one Job Header Record (DB: WebDumper TBL:
CustomerUploadHeader)
'
Each Customer Job has one or more Transcript Header Records (DB: WebDumper TBL:
CustomerUploadFiles)
'
Each set of uploaded files should reside in a direcory named after the
Transcript Header Id
'
All the Transcript Header Id Directories should be complessed into a single file
named by the "Job Number"
'
Direcory Structure:
'
"Project Code" (dir)
'
--> "Job Number" (dir)
'
--> --> "Job Number".ZIP (compressed file)
'
--> -->
-->
"Transcript Header Id" (dir)
'
--> --> -->
--> *.* (audio and text
files)
End Sub
Public Function
BuildAbsoluteUri(ByVal relativeUri
As String)
As Uri
' Get current absolute Uri; this depends on where the
app is deployed
Dim uri1 As Uri
= System.Windows.Browser.HtmlPage.Document.DocumentUri
Dim uriString As
String = uri1.AbsoluteUri
' Replace page name with relative service Uri
Dim ls As Int32
= uriString.LastIndexOf("/"c)
uriString = uriString.Substring(0, ls + 1) + relativeUri
' Return new Uri
Return New
Uri(uriString, UriKind.Absolute)
End Function
Private _jobNumber As
Nullable(Of Integer)
Public Property
jobNumber() As Nullable(Of Integer)
Get
Return _jobNumber
End Get
Set(ByVal value
As Nullable(Of
Integer))
_jobNumber = value
End Set
End Property
Private Sub
MainPage_Loaded(ByVal sender
As Object,
ByVal e As
System.Windows.RoutedEventArgs) Handles
Me.Loaded
Debug.Assert(sender IsNot
Nothing, "sender is
null.")
Debug.Assert(e IsNot
Nothing, "e is null.")
HtmlPage.RegisterScriptableObject("SilverlightComponentOne",
Me)
''
Scriptable Member accessible by JavaScript/Ajax and Silverlight interface
''
loadtranscriptheaderdropdownlist(jobNumber)
End Sub
<ScriptableMember()> _
Sub cboTranscriptHeader_Load(ByVal jobnumber As
String)
'ToDo: A cleaner way to go from String to Nullable
Integer?
Dim _value As
Integer
If Integer.TryParse(jobnumber,
_value) Then
_jobNumber = _value
Else
_jobNumber = Nothing
End If
Dim ws As
SilverlightApplicationUploader.SLC1WebService.SlC1WebServiceSoapClient = _
New
SilverlightApplicationUploader.SLC1WebService.SlC1WebServiceSoapClient()
Dim request As
New
SLC1WebService.GetTranscriptHeaderRecordsRequest(Me.jobNumber)
AddHandler
ws.GetTranscriptHeaderRecordsCompleted, AddressOf
ws_GetTranscriptHeaderRecords
ws.GetTranscriptHeaderRecordsAsync(request)
End Sub
Private Sub
ws_GetTranscriptHeaderRecords(ByVal sender
As Object, _
ByVal e As
SLC1WebService.GetTranscriptHeaderRecordsCompletedEventArgs)
Me.cboTranscriptHeader.Items.Clear()
For Each record
As
SilverlightApplicationUploader.SLC1WebService.vwTranscriptHeaderRecords
In e.Result.GetTranscriptHeaderRecordsResult
Me.cboTranscriptHeader.Items.Add(record.Filename)
Next
End Sub
#End
Region '"** event
handling"
''
-------------------------------------------------------------------------------------
End
Class
C. The client config
<?xml
version="1.0"
encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding
name="SlC1WebServiceSoap" closeTimeout="00:01:00" openTimeout="00:01:00"
receiveTimeout="00:10:00"
sendTimeout="00:01:00"
maxBufferSize="2147483647"
maxReceivedMessageSize="2147483647"
textEncoding="utf-8" >
<security
mode="None"/>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint
address="http://localhost:2443/SlC1WebService.asmx"
binding="basicHttpBinding"
bindingConfiguration="SlC1WebServiceSoap"
contract="SLC1WebService.SlC1WebServiceSoap" name="SlC1WebServiceSoap" />
</client>
</system.serviceModel>
</configuration>
D. The Silverlight Control xaml
<UserControl x:Class="SilverlightApplicationUploader.SilverlightControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:data="clr-namespace:SilverlightApplicationUploader.SLC1WebService"
Width="400" Height="300">
<UserControl.Resources>
<Style x:Key="ControlBorder"
TargetType="Border">
<Setter Property="BorderThickness"
Value="3" />
<Setter Property="Background"
Value="#FFC2F5CB" />
<Setter Property="BorderBrush"
Value="#FF257004" />
<Setter Property="CornerRadius"
Value="6" />
<Setter Property="Margin"
Value="5" />
<Setter Property="Padding"
Value="5" />
</Style>
<Style x:Key="ControlTitle"
TargetType="TextBlock">
<Setter Property="FontSize"
Value="14" />
<Setter Property="HorizontalAlignment"
Value="Center" />
<Setter Property="FontFamily"
Value="Courier New" />
<Setter Property="FontWeight"
Value="Bold" />
<Setter Property="Foreground"
Value="#FF1F6900" />
</Style>
</UserControl.Resources>
<Grid x:Name="LayoutRoot"
Background="White">
<ScrollViewer>
<StackPanel x:Name="_mainPanel"
Margin="6" >
<Border Style="{StaticResource ControlBorder}">
<StackPanel>
<TextBlock x:Name="DisplayTranscriptHeader"
Text="TranscriptHeader" Style="{StaticResource ControlTitle}" />
<StackPanel Orientation="Horizontal"
Height="50">
<ComboBox x:Name="cboTranscriptHeader"
Width="80" Height="30"
VerticalAlignment="Top" Margin="5"
SelectionChanged="cboTranscriptHeader_ItemSelected"
ItemsSource="{Binding Mode=OneWay}" >
<ComboBoxItem Content="CaseFileNumber" />
</ComboBox>
</StackPanel>
</StackPanel>
</Border>
</StackPanel>
</ScrollViewer>
</Grid>
</UserControl>
E. The Application Class
Partial
Public Class App
Inherits Application
public
Sub New()
InitializeComponent()
End Sub
Private Sub
Application_Startup(ByVal o
As Object,
ByVal e As
StartupEventArgs) Handles
Me.Startup
Dim JobNumber As
String = e.InitParams("JobNumber")
Me.RootVisual = New
SilverlightControl1(JobNumber)
End Sub
Private Sub
Application_Exit(ByVal o
As Object,
ByVal e As
EventArgs) Handles Me.Exit
End Sub
Private Sub
Application_UnhandledException(ByVal sender
As object,
ByVal e As
ApplicationUnhandledExceptionEventArgs) Handles
Me.UnhandledException
' If the app is running outside of the debugger then
report the exception using
' the browser's exception mechanism. On IE this will
display it a yellow alert
' icon in the status bar and Firefox will display a
script error.
If Not
System.Diagnostics.Debugger.IsAttached Then
' NOTE: This will allow the application to
continue running after an exception has been thrown
' but not handled.
' For production applications this error
handling should be replaced with something that will
' report the error to the website and stop the
application.
e.Handled = True
Deployment.Current.Dispatcher.BeginInvoke(New
Action(Of
ApplicationUnhandledExceptionEventArgs)(AddressOf
ReportErrorToDOM), e)
End If
End Sub
Private Sub ReportErrorToDOM(ByVal e As
ApplicationUnhandledExceptionEventArgs)
Try
Dim errorMsg As
String = e.ExceptionObject.Message +
e.ExceptionObject.StackTrace
errorMsg = errorMsg.Replace(""""c,
"'"c).Replace(ChrW(13) & ChrW(10), "\n")
System.Windows.Browser.HtmlPage.Window.Eval("throw
new Error(""Unhandled Error in Silverlight Application " + errorMsg +
""");")
Catch
End Try
End Sub
End
Class
F. The Application xaml
<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SilverlightApplicationUploader.App"
>
<Application.Resources>
</Application.Resources>
</Application>
G. The client access policy
<?xml
version="1.0"
encoding="utf-8" ?>
<access-policy>
<cross-domain-access>
<policy>
<allow-from
http-request-headers="*">
<!--/*Specify
request headers like Content-Type,SOAPAction*/-->
<domain
uri="*"/>
</allow-from>
<grant-to>
<resource
include-subpaths="true"
path="/"/>
</grant-to>
</policy>
</cross-domain-access>
</access-policy>
H. The cross domain policy
<?xml
version="1.0"
encoding="utf-8" ?>
<cross-domain-policy>
<allow-http-request-headers-from
domain="*" headers="*"/>
</cross-domain-policy>
I. The Web Service
<System.Web.Services.WebService(Namespace:="http://localhost:2443/")>
_
<System.Web.Services.WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)>
_
<ToolboxItem(False)> _
Public
Class SlC1WebService
Inherits System.Web.Services.WebService
<WebMethod()> _
Public Function
GetTranscriptHeaderRecords(ByVal jobNumber
As Global.System.Nullable(Of Integer))
As List(Of
vwTranscriptHeaderRecords)
'ToDo: Call this method from SL passing JobNumber and
Retreiving list of transcriptHeaders
Dim transcriptHeaders
As New List(Of
vwTranscriptHeaderRecords)
Dim de As
New StenoMainEntities
' Execute the query and get the
ObjectQueryResult.
Dim TranscriptHeaderRecordsResult
As Objects.ObjectResult(Of vwTranscriptHeaderRecords) =
de.GetTranscriptHeaderRecords(jobNumber)
' Iterate through the collection of Product items.
Dim result As
vwTranscriptHeaderRecords
For Each result
In TranscriptHeaderRecordsResult
transcriptHeaders.Add(result)
Next
Return transcriptHeaders
End Function
End
Class
<summary>
''' Parameter class
'''
</summary>
Public
Class Parameter
Private _Key As
String
Public Property
Key() As String
Get
Return _Key
End Get
Set(ByVal value
As String)
_Key = value
End Set
End Property
Private _Value As
String
Public Property
Value() As String
Get
Return _Value
End Get
Set(ByVal value
As String)
_Value = value
End Set
End Property
End
Class
Public
Partial Class
TestGetTranscriptHeader
Inherits System.Web.UI.Page
Protected Sub
Page_Load(ByVal sender
As Object, ByVal
e As System.EventArgs)
Handles Me.Load
Dim jobNumber As
Nullable(Of Integer)
= 520124
Dim transcriptHeaders
As New List(Of
vwTranscriptHeaderRecords)
Dim de As
New DBEntities
' Execute the query and get the ObjectQueryResult.
Dim TranscriptHeaderRecordsResult
As Objects.ObjectResult(Of vwTranscriptHeaderRecords) =
de.GetTranscriptHeaderRecords(jobNumber)
' Iterate through the collection of Product items.
Dim result As
vwTranscriptHeaderRecords
For Each result
In TranscriptHeaderRecordsResult
transcriptHeaders.Add(result)
Next
Response.Write("Results" & vbCrLf)
For Each result
In transcriptHeaders
Response.Write("-" & result.JobNumber
& ", " & result.Filename & vbCrLf)
Next
End Sub
End Class
No comments:
Post a Comment