|
DbSet should only ever be referenced in your DbContext class.
The query is easy enough but I have no idea what you're function header is saying or asking for. So, here's what a query normally looks like:
Public Shared Function GetAllMovies() As IEnumerable(Of MovieItem)
Using context As New MovieContext()
Dim results = From item In context.Movies
Where item.flv = 1
Order By item.MovieName
Select New MovieItem With
{
.MovieId = item.MovieId,
.MovieName = item.MovieName,
...
}
Return results.AsEnumerable()
End Using
End Function
|
|
|
|
|
Thanks Dave! Thats exactly what I wanted to do. Say would it be possible to validate my Context, I may be way off on it.
I get this error after using the iEnumerator(of MovieContext) in your reply:
Unable to cast object of type 'System.Data.Entity.Infrastructure.DbQuery1[VB$AnonymousType_0 19[System.Int32,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.Int32,System.String,System.DateTime,System.String,System.String]]' to type 'System.Collections.Generic.IEnumerable`1[dataAccessLayer.DAL.MovieContext]'.
Does 19 mean column 19?
Imports System.Data.Entity
Imports System.Data.Entity.ModelConfiguration.Conventions
Imports dataAccessLayer.Models
Namespace DAL
Public Class MovieContext
Inherits DbContext
Public Sub New()
MyBase.New("MovieContext")
Database.SetInitializer(New CreateDatabaseIfNotExists(Of MovieContext))
Entity.Database.SetInitializer(Of MovieContext)(Nothing)
End Sub
Public Property Movies As DbSet(Of Movies)
Public Property Movies_flv As DbSet(Of Movies_flv)
Public Property Movies_h264 As DbSet(Of Movies_h264)
Protected Overrides Sub OnModelCreating( _
ByVal modelBuilder As DbModelBuilder)
modelBuilder.Conventions.Remove(Of PluralizingTableNameConvention)()
End Sub
End Class
End Namespace
|
|
|
|
|
The "19" doesn't mean anything in this case.
The error says that you're trying to convert an anonymous type (your Select New ...) into an IEnumerable(Of MovieContext). You're saying that the function is returning a list of MovieContext. So, your function header is wrong. You should be returning an IEnumerable of whatever type your Select is projecting into. In my example, I specifically said something like MovieItem, whereas you're returning an anonymous type.
|
|
|
|
|
I didn't pay careful enough attention to your example and just saw what I wanted to see.
I understand what the MovieItem is.
Public Shared Function load_movie_array( _
ByVal pSortOrder As SortOrder,
ByVal pType As MovieType) As IEnumerable(Of MovieItem)
Using context As New MovieContext()
Dim results =
From item In context.Movies
Where item.flv = 1
Order By item.MovieName
Select New MovieItem With
{
.MovieID = item.MovieID,
.MovieName = item.MovieName,
.MovieType = item.MovieType,
.MovieDeliveryType = item.MovieDeliveryType,
.MoviePath = item.MoviePath,
.MovieURL = item.MovieURL,
.MoviePostage = item.MoviePostage,
.MovieThumbnail = item.MovieThumbnail,
.MovieLarge = item.MovieLarge,
.MoviePlaceHolder = item.MoviePlaceHolder,
.MovieBitRate = item.MovieBitRate,
.MovieTime = item.MovieTime,
.MovieSize = item.MovieSize,
.MovieDescription = item.MovieDescription,
.MovieCount = item.MovieCount,
.MovieContributor = item.MovieContributor,
.MoviePostDate = item.MoviePostDate,
.MovieIcon = item.MovieIcon,
.movie_Parameters = item.movie_Parameters
}
Return results.AsEnumerable()
End Using
End Function
|
|
|
|
|
Oh, I have to project the results into another object like a class or something, to transport it.
I thought that's what the model was for. Or does the model just works with the context, in order to create or update the database table?
|
|
|
|
|
jkirkerx wrote: I have to project the results into another object like a class or something, to transport it.
You don't have to but it makes your code easier to understand, debug and support.
jkirkerx wrote: I thought that's what the model was for
You can return just the model objects. It appears as though you're just returning every field of the Movie table, so you can just return an IEnumerable(Of Movie) instead of projecting into another object.
Public Shared Function GetAllFlvMovies() As IEnumerable(Of Movie)
Using context As New MovieContext()
Dim results = From m In context.Movies
Where item.flv = 1
Order By m.MovieName
Select m
Return results.AsEnumerable()
End Using
End Function
Projection comes in handy when you are building view model objects. You only put the data you need into the view model object and possibly more data that isn't related to the database to supply your edit controls with.
...
Dim movies = From item In GetAllFlvMovies()
Select New MovieViewModel With
{
Id = item.MovieId,
Name = item.MovieName,
...
}
... send the <code>movies</code> collection to whatever view you need ...
|
|
|
|
|
Thanks Dave, I owe you as well for the price of tuition on schooling me today.
I got more than expected today, and the complete index works, plus I know that my DAL seems to be working as well including the model.
I'm pretty excited right now. I think this DAL experiment is going to work out great in the long run for me, and is the way to go moving forward.
So on to Updates, inserts and deletes, plus joins as well. Then I can get depressed again!
I'll be back.
|
|
|
|
|
|
I'm trying to figure out how to get the count of records. I was just expecting the other fucntion to give me a count as IEnumerable, but it doesn't provide it.
So I wrote this, not sure if it's right, because I get 0 back, and there's 4
Do you think this is because the database was already existing, and it's related to Code First.
On the previous function, I'm not sure if I'm getting data back or not, and not quite sure how to use the returned output.
This calls the previous function in the post above. I didn't want to repost it again.
Dim m_count As Integer = shared_MovieInfo.get_index_count(shared_MovieInfo.MovieType.FLV)
Dim movies As IEnumerable(Of MovieItem)
movies = shared_MovieInfo.load_index_array(shared_MovieInfo.SortOrder.Name, shared_MovieInfo.MovieType.FLV)
So I'm thinking you just use it like this
For Each m As Object In movies
Dim m_MovieName_Encoded As String = System.Web.HttpUtility.HtmlEncode(m.MovieName)
Next
Count Function that I wrote. I tried the shorter method, but the MovieContext wasn't shared, said the compiler.
Not sure what to do with that message, But I get 0 back as a result.
I really wanted to use just 1 function for the data and the count.
Public Shared Function get_index_count( _
ByVal pType As MovieType) As Integer
Dim context As New MoviesContext()
Dim pValue = (From item In context.Movies
Where item.flv = 1
Select item).Count()
Return pValue
End Function
|
|
|
|
|
jkirkerx wrote: So I wrote this, not sure if it's right, because I get 0 back, and there's 4
Wrote what?
jkirkerx wrote: Do you think this is because the database was already existing, and it's related to Code First.
Not a chance.
jkirkerx wrote: On the previous function, I'm not sure if I'm getting data back or not, and not quite sure how to use the returned output.
If the count is 0, you're not getting back any data. The Where clause of your query is probably what's screwing it up.
Quote: For Each m As Object In movies
Dim m_MovieName_Encoded As String = System.Web.HttpUtility.HtmlEncode(m.MovieName)
Next
Uhhhh, what does this have to do with a Count or a list of movies?
jkirkerx wrote: Count Function that I wrote.
Yeah, there's no need for that function at all. Also, you're hitting the database a second time for one value.
I really have no idea what the rest of your code looks like, but, based on what you've posted so far, I think it's a giant over-complicated mess. Sorry, but I'm not following what you're code is doing related to a Movie database and your method and variable names don't make sense to me at all. Also, why do you have 3 different tables of movies? From what I saw in your DbContext class, there should be only one.
|
|
|
|
|
Dave Kreskowiak wrote: Uhhhh, what does this have to do with a Count or a list of movies?
This is just the start of the experiment. This is for a movie index, with page numbers and show selections. I have to calculate the start index and stop index.
Dave Kreskowiak wrote: Do you think this is because the database was already existing, and it's related to Code First.
This is new to me, I read the term a couple of times. I did have to delete a column and recreate it for the "Invalid Column Name" error.
The database is 7 years old, but has been changed 3 times.
Dave Kreskowiak wrote: Uhhhh, what does this have to do with a Count or a list of movies?
That is just a small snippet, a loop that builds the a cell for the movie information.
This is what I get back in the program that calls the function to load the Movie records. I thought I would get a data set back, but it looks like a some sort of query that is ready to go, but just needs to be executed or something.
Sorry I sound so dumb on this, but this is the 2nd time I've done this. the first time, someone else wrote the DAL dll and the database, and I just wrote the Linq for it in a windows app.
Hey thanks for helping me and steering me straight on this. If I could just get something working, even just the count, then everything should come together on the mechanics of it.
{SELECT
[Extent1].[MovieID] AS [MovieID],
[Extent1].[MovieName] AS [MovieName],
[Extent1].[MovieType] AS [MovieType],
[Extent1].[MovieDeliveryType] AS [MovieDeliveryType],
[Extent1].[MoviePath] AS [MoviePath],
[Extent1].[MovieURL] AS [MovieURL],
[Extent1].[MoviePostage] AS [MoviePostage],
[Extent1].[MovieThumbnail] AS [MovieThumbnail],
[Extent1].[MovieLarge] AS [MovieLarge],
[Extent1].[MoviePlaceHolder] AS [MoviePlaceHolder],
[Extent1].[MovieBitRate] AS [MovieBitRate],
[Extent1].[MovieTime] AS [MovieTime],
[Extent1].[MovieSize] AS [MovieSize],
[Extent1].[MovieDescription] AS [MovieDescription],
[Extent1].[MovieCount] AS [MovieCount],
[Extent1].[MovieContributor] AS [MovieContributor],
[Extent1].[MoviePostDate] AS [MoviePostDate],
[Extent1].[MovieIcon] AS [MovieIcon],
[Extent1].[movie_Parameters] AS [movie_Parameters]
FROM [dbo].[MOVIEINFO] AS [Extent1]
WHERE 1 = [Extent1].[flv]
ORDER BY [Extent1].[MovieName] ASC}
|
|
|
|
|
Well I got the count finally.
I misunderstood the Context, Sub New, MyBase.New and put a conn string in it.
Question: I use the connStr below in my original stuff, possible to use that again, or how do you do it?
Public Sub New()
MyBase.New("Data Source=XXXXXXXX; Initial Catalog=XXXXXXX; User ID=XXXXXXX; Password=XXXXX;")
Dim connStr As String = ConfigurationManager.ConnectionStrings("DefaultConnection").ConnectionString
Database.SetInitializer(New CreateDatabaseIfNotExists(Of MoviesContext))
Entity.Database.SetInitializer(Of MoviesContext)(Nothing)
End Sub
And I rewrote my function, that I place in the DAL Dll. So now I get the count of 4
Public Shared Function load_index_array( _
ByVal pSortOrder As SortOrder,
ByVal pType As MovieType,
ByRef pResults As IEnumerable(Of MovieItem)) As Integer
Dim context As New MoviesContext()
pResults =
(From item In context.Movies
Select New MovieItem With
{
.MovieID = item.MovieID,
.MovieName = item.MovieName,
.MovieType = item.MovieType,
.MovieDeliveryType = item.MovieDeliveryType,
.MoviePath = item.MoviePath,
.MovieUrl = item.MovieURL,
.MoviePostage = item.MoviePostage,
.MovieThumbnail = item.MovieThumbnail,
.MovieLarge = item.MovieLarge,
.MoviePlaceHolder = item.MoviePlaceHolder,
.MovieTime = item.MovieTime,
.MovieSize = item.MovieSize,
.MovieDescription = item.MovieDescription,
.MovieCount = item.MovieCount,
.MovieContributor = item.MovieContributor,
.MoviePostDate = item.MoviePostDate,
.MovieIcon = item.MovieIcon,
.MovieParameters = item.movie_Parameters
}).AsEnumerable
Return pResults.Count()
End Function
|
|
|
|
|
I put the connection string in the App.config/Web.config file, never in the code itself.
An example DbContext I wrote looks like this:
public class MyContext : DbContext
{
public MyContext()
{
}
public MyContext(string connectionStringName)
: base(connectionStringName)
{
}
public override int SaveChanges()
{
ChangeTracker.DetectChanges();
return base.SaveChanges();
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
ConfigureModel(modelBuilder);
base.OnModelCreating(modelBuilder);
}
private void ConfigureModel(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new SomethingConfiguration());
modelBuilder.Configurations.Add(new SomethingElseConfiguration());
modelBuilder.Configurations.Add(new SomeOtherTableConfiguration());
...
}
public DbSet<sometype> SomeTypes { get; set; }
public DbSet<othertype> OtherTypes { get; set; }
public DbSet<contact> Contacts { get; set; }
...
}
}
<div class="signature"><a href="http://www.codeproject.com/scrapbook/ForumGuidelines.asp">A guide to posting questions on CodeProject</a><br><br>Click this: <a href="http://weblogs.asp.net/bleroy/asking-questions-is-a-skill">Asking questions is a skill</a>.
Seriously, do it.<br>
<font color="Blue">Dave Kreskowiak</font></div>
|
|
|
|
|
I used ConfigurationManager.ConnectionStrings("DefaultConnection").ConnectionString
as the conn string in my new in context. But I changed to your version, You must have a good reason for it; I'll learn down the as to why.
So I guess when using context as new context(connStr), using and not Dim in VB
The results I project are lost, because the context is disposed.
Is it good practice to create a new context and just pass it along? with using. I think that would get disposed as well.
OK, Thanks for the example above. I'll move on to the actual queries now.
I figured out that sql parameters are created automatically.
|
|
|
|
|
jkirkerx wrote: I used ConfigurationManager.ConnectionStrings("DefaultConnection").ConnectionString
as the conn string in my new in context. But I changed to your version, You must have a good reason for it; I'll learn down the as to why.
Because DbContext already uses the ConfigurationManager stuff itself. All you need to supply, if anything at all, is the name of the connection string in your App.config/Web.config file. Putting the connection string in the config file is also best practice.
jkirkerx wrote: Is it good practice to create a new context and just pass it along? with using. I think that would get disposed as well.
Best practice for database access is always connect as late as possible, run your queries, and disconnect as early as possible and dispose your objects.
With Entity Framework, that's easy. Create your DbContext instance with a using block and put your query code in there. The using block will automatically Dispose of the context when execution leaves the block.
|
|
|
|
|
Well, I thought IEnumerable would be used for single records as well. Guess Not.
So I put this together, and just used the class straight.
I'm pretty sure my Linq is correct, but MovieRecord class is empty.
Am I even close on this?
Public Shared Function load_movie_record( _
ByVal p_MovieID As Integer,
ByRef pResults As MovieRecord) As Integer
Dim context As New MoviesContext()
pResults =
( _
From m In context.Movies
Join f In context.Movies_flv On m.MovieID Equals f.movieID
Join h In context.Movies_h264 On m.MovieID Equals h.movieID
Where m.MovieID = p_MovieID
Select New MovieRecord With {
.MovieID = m.MovieID,
.MovieName = m.MovieName,
.MovieType = m.MovieType,
.flvID = f.ID,
.flvMovieID = f.movieID,
.flvMovieName = f.flv_movieName,
.h264ID = f.ID,
.h264MovieID = h.movieID,
.h264MovieName = h.h264_movieName,
}).SingleOrDefault()
|
|
|
|
|
If the pResults is null or empty it means your query didn't come back with any records. The value you're passing to the Where clause would be the first thing to check and then see if the record actually exists in the database.
|
|
|
|
|
My Bad, I copy a newer version of MovieInfo over to the test database server, and forgot to copy the 2 join tables over, so there were no matches.
|
|
|
|
|
I need to print from rdlc without preview. I runs well when report is previewed with ReportViewer.
However, I have searched and copied from all available sources of "printing RDLC without preview but when i run my code I receive the error, "An error occurred during local report processing"
this occurs at the
report.Render("IMAGE", deviceInfo, AddressOf CreateStream, warnings)
below is my entire code
Imports System
Imports System.IO
Imports System.Data
Imports System.Text
Imports System.Drawing
Imports System.Drawing.Printing
Imports System.Collections.Generic
Imports System.Windows.Forms
Imports Microsoft.Reporting.WinForms
Imports System.Drawing.Imaging
Module modul_print_reports
Private m_currentPageIndex As Integer
Private m_streams As IList(Of Stream)
Private printDoc As PrintDocument
''' <summary>
''' Print rdlc report with custom page width and height
''' </summary>
''' <param name="report"></param>
''' <param name="page_width">the width of the papger, in hunderdths of an inch</param>
''' <param name="page_height">the height of the papger, in hunderdths of an inch</param>
''' <param name="islandscap"></param>
''' <param name="printer_name">Ignore this parameter to use default printer</param>
''' <remarks></remarks>
Public Sub print_microsoft_report(ByRef report As LocalReport, ByVal page_width As Integer, ByVal page_height As Integer, _
Optional ByVal islandscap As Boolean = False, _
Optional ByVal printer_name As String = Nothing)
printDoc = New PrintDocument()
If printer_name <> Nothing Then printDoc.PrinterSettings.PrinterName = printer_name
If Not printDoc.PrinterSettings.IsValid Then ' detecate is the printer is exist
Throw New Exception("Cannot find the specified printer")
Else
Dim ps As New PaperSize("Custom", page_width, page_height)
printDoc.DefaultPageSettings.PaperSize = ps
printDoc.DefaultPageSettings.Landscape = islandscap
Export(report)
Print()
End If
End Sub
''' <summary>
''' Print rdlc report with specific paper kind
''' </summary>
''' <param name="report"></param>
''' <param name="paperkind">String paper Kind, ex:"letter"</param>
''' <param name="islandscap"></param>
''' <param name="printer_name">Ignore this parameter to use default printer</param>
''' <remarks></remarks>
Public Sub print_microsoft_report(ByVal report As LocalReport, Optional ByVal paperkind As String = "A4", _
Optional ByVal islandscap As Boolean = False, _
Optional ByVal printer_name As String = Nothing)
printDoc = New PrintDocument()
If printer_name <> Nothing Then printDoc.PrinterSettings.PrinterName = printer_name
If Not printDoc.PrinterSettings.IsValid Then ' detecate is the printer is exist
Throw New Exception("Cannot find the specified printer")
Else
Dim ps As PaperSize
Dim pagekind_found As Boolean = False
For i = 0 To printDoc.PrinterSettings.PaperSizes.Count - 1
If printDoc.PrinterSettings.PaperSizes.Item(i).Kind.ToString = paperkind Then
ps = printDoc.PrinterSettings.PaperSizes.Item(i)
printDoc.DefaultPageSettings.PaperSize = ps
pagekind_found = True
End If
Next
If Not pagekind_found Then Throw New Exception("paper size is invalid")
printDoc.DefaultPageSettings.Landscape = islandscap
Export(report)
Print()
End If
End Sub
' Routine to provide to the report renderer, in order to
' save an image for each page of the report.
Private Function CreateStream(ByVal name As String, ByVal fileNameExtension As String, _
ByVal encoding As Encoding, ByVal mimeType As String, ByVal willSeek As Boolean) As Stream
Dim stream As Stream = New MemoryStream()
m_streams.Add(stream)
Return stream
End Function
' Export the given report as an EMF (Enhanced Metafile) file.
Private Sub Export(ByVal report As LocalReport)
Dim w As Integer
Dim h As Integer
If printDoc.DefaultPageSettings.Landscape = True Then
w = printDoc.DefaultPageSettings.PaperSize.Height
h = printDoc.DefaultPageSettings.PaperSize.Width
Else
w = printDoc.DefaultPageSettings.PaperSize.Width
h = printDoc.DefaultPageSettings.PaperSize.Height
End If
Dim deviceInfo As String = "<DeviceInfo>" & _
"<OutputFormat>EMF</OutputFormat>" & _
"<PageWidth>" & w / 100 & "in</PageWidth>" & _
"<PageHeight>" & h / 100 & "in</PageHeight>" & _
"<StartPage>0</StartPage><EndPage>0</EndPage><MarginTop>0.0in</MarginTop>" & _
"<MarginLeft>0.0in</MarginLeft>" & _
"<MarginRight>0.0in</MarginRight>" & _
"<MarginBottom>0.0in</MarginBottom>" & _
"</DeviceInfo>"
Dim warnings As Warning()
m_streams = New List(Of Stream)()
'Dim byt As Byte() = report.Render("IMAGE")
report.Render("IMAGE", deviceInfo, AddressOf CreateStream, warnings)
For Each stream As Stream In m_streams
stream.Position = 0
Next
End Sub
' Handler for PrintPageEvents
Private Sub PrintPage(ByVal sender As Object, ByVal ev As PrintPageEventArgs)
Dim pageImage As New Metafile(m_streams(m_currentPageIndex))
' Adjust rectangular area with printer margins.
Dim adjustedRect As New Rectangle(ev.PageBounds.Left - CInt(ev.PageSettings.HardMarginX),
ev.PageBounds.Top - CInt(ev.PageSettings.HardMarginY), _
ev.PageBounds.Width, _
ev.PageBounds.Height)
' Draw a white background for the report
ev.Graphics.FillRectangle(Brushes.White, adjustedRect)
' Draw the report content
ev.Graphics.DrawImage(pageImage, adjustedRect)
' Prepare for the next page. Make sure we haven't hit the end.
m_currentPageIndex += 1
ev.HasMorePages = (m_currentPageIndex < m_streams.Count)
End Sub
Private Sub Print()
If m_streams Is Nothing OrElse m_streams.Count = 0 Then
Throw New Exception("Error: no stream to print.")
End If
AddHandler printDoc.PrintPage, AddressOf PrintPage
m_currentPageIndex = 0
printDoc.Print()
End Sub
End Module
cn.Open()
Dim cmd = New SqlCommand("SELECT [BatchNo]," +
"[ProdID],[ProdName],[MfgDate],[ExpDate],[ImgName],[ImgPath],[UserID],[FullName]" +
"FROM dbo.vwBatchRecs WHERE [BatchNo]=@bn ORDER BY [ImgName]", cn)
cmd.Parameters.Clear()
cmd.Parameters.AddWithValue("@bn", pf_Id)
Dim dr = cmd.ExecuteReader()
Dim dt As New DataTable
dt.Load(dr)
Dim rpt As New LocalReport
rpt.DataSources.Clear()
rpt.EnableExternalImages = True
rpt.ReportEmbeddedResource = "PharmaDoc.BatchPrep.rdlc"
rpt.ReportPath = "BatchPrep.rdlc"
rpt.DataSources.Add(New ReportDataSource("vwBatchRecs", dt)) '
rpt.Refresh()
dr.Close()
cmd.Dispose()
cn.Close()
'rpt.SetDisplayMode(DisplayMode.PrintLayout)
'rpt.ZoomMode = ZoomMode.FullPage
'Dim cp As New Reportprint
print_microsoft_report(rpt)
I have also tried the following source but still same problem <a href="https://msdn.microsoft.com/en-us/library/ms252091%28v=vs.100%29.aspx">https://msdn.microsoft.com/en-us/library/ms252091%28v=vs.100%29.aspx</a>[<a href="https://msdn.microsoft.com/en-us/library/ms252091%28v=vs.100%29.aspx" target="_blank" title="New Window">^</a>]
|
|
|
|
|
Hello!
I need help please! I have no experience in programming or whatsoever and I have been sent this excel file to execute macros. But somehow it doesn't work and the message Excel VBA Function runtime error 1004: Application-defined or object-defined error message keeps appearing. I don't know what's wrong or how to fix it...
Columns("A:A").Select
Selection.TextToColumns Destination:=Range("A1"), DataType:=xlDelimited, _
TextQualifier:=xlDoubleQuote, ConsecutiveDelimiter:=False, Tab:=True,_
Semicolon:=False, Comma:=False, Space:=False, Other:=True, OtherChar _
:="<", FieldInfo:=Array(Array(1, 1), Array(2, 1), Array(3, 1)), _
TrailingMinusNumbers:=True
This is the highlighted part. Is there something wrong with the coding? Or is it because the file was created on non-Mac laptop and I am using Mac?
Please help, I would really appreciate it! Thank you!
|
|
|
|
|
You would probably get a faster answer by going back to the person who sent you the file.
|
|
|
|
|
Hi,
My vb application is going to call a DoPrint function in a dll file.
The dll to notify the vb application when the printing is done.
I'm trying to us the below:
Public Delegate Sub Action(Of T) (obj As T)
But not sure how to imlement it.
Does anyone have a suggestion or a working example ?
Thanks
|
|
|
|
|
|
Perhaps there's someone out there that has done FirstData G4 SOAP V14 in VB, and can checkout or point out any mistakes I made.
So I get this error upon transmitting
The HTTP request is unauthorized with client authentication scheme 'Anonymous'. The authentication header received from the server was ''.
So I'm figuring my HMAC header authentication is way off, and i get a generic response back.
I have a XML version that works just fine. And the G4 Sandbox has a HMAC Calculator tool, that I can use to compare and generate the values.
Issue 1:
But I'm not sure if what I'm pasting in as content is correct, in order to validate the code block, 2 blocks below.
example: Not sure if this is the correct format of SOAP Content, so I can run the FirstData HMAC Generate to confirm my values are right.
I using the same code sort of, to generate the HMAC stuff.
I just can't get a match of values, I'm way off, so I'm thinking that the SOAP content I generating against is wrong, in size and all.
If I fix issue 1, perhaps the rest of my code works fine.
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<q1:SendAndCommit xmlns:q1="http://secure2.e-xact.com/vplug-in/transaction/rpc-enc/Request">
<SendAndCommitSource href="#id1"/>
</q1:SendAndCommit>
<q2:Transaction id="id1" xsi:type="q2:Transaction" xmlns:q2="http://secure2.e-xact.com/vplug-in/transaction/rpc-enc/encodedTypes">
<ExactID xsi:type="xsd:string">AH2824-05</ExactID>
<Password xsi:type="xsd:string">0g4tu7pj1hb88q5d8xa55dlhvhvwlm3r</Password>
<Transaction_Type xsi:type="xsd:string">00</Transaction_Type>
<DollarAmount xsi:type="xsd:string">99.20</DollarAmount>
<Card_Number xsi:type="xsd:string">4111111111111111</Card_Number>
<Expiry_Date xsi:type="xsd:string">1215</Expiry_Date>
<CardHoldersName xsi:type="xsd:string">Joe Smoe</CardHoldersName>
<CVDCode xsi:type="xsd:string">999</CVDCode>
<Reference_No xsi:type="xsd:string">CA-Test4</Reference_No>
<Client_IP xsi:type="xsd:string">::1</Client_IP>
<Client_Email xsi:type="xsd:string">xxxxxxx@gmail.com</Client_Email>
<Currency xsi:type="xsd:string">USD</Currency>
<Address href="#id2"/>
</q2:Transaction>
<q3:Address_Type id="id2" xsi:type="q3:Address_Type" xmlns:q3="http://secure2.e-xact.com/vplug-in/transaction/rpc-enc/encodedTypes">
<Address1 xsi:type="xsd:string">1234 Main Street</Address1>
<Address2 xsi:type="xsd:string"/>
<City xsi:type="xsd:string">Huntington Beach</City>
<State xsi:type="xsd:string">CA</State>
<Zip xsi:type="xsd:string">92648</Zip>
<CountryCode xsi:type="xsd:string">US</CountryCode>
</q3:Address_Type>
</s:Body>
</s:Envelope>
Issue 2:
This is my BeforeSendRequest. Im not sure how to check the SOAP to make sure if the header has been altered properly before transmitting, but the handler does run.
Public Function BeforeSendRequest( _
ByRef request As Message,
ByVal channel As IClientChannel) As Object Implements IClientMessageInspector.BeforeSendRequest
Dim buffer As MessageBuffer = request.CreateBufferedCopy(Int32.MaxValue)
request = buffer.CreateMessage
Dim msg As Message = buffer.CreateMessage
Dim encoder As ASCIIEncoding = New ASCIIEncoding
Dim sb As StringBuilder = New StringBuilder
Dim xmlSettings As New XmlWriterSettings
xmlSettings.OmitXmlDeclaration = True
Dim xmlWriter As XmlWriter = xmlWriter.Create(sb, xmlSettings)
Dim writer As XmlDictionaryWriter = XmlDictionaryWriter.CreateDictionaryWriter(xmlWriter)
msg.WriteStartEnvelope(writer)
msg.WriteStartBody(writer)
msg.WriteBodyContents(writer)
xmlWriter.WriteEndElement()
xmlWriter.WriteEndElement()
writer.Flush()
Dim body As String = sb.ToString.Replace(" />", "/>")
Dim xml_bytes() As Byte = encoder.GetBytes(body)
Dim sha1_crypto As SHA1CryptoServiceProvider = New SHA1CryptoServiceProvider
Dim hash As String = BitConverter.ToString(sha1_crypto.ComputeHash(xml_bytes)).Replace("-", "")
Dim hashed_content As String = hash.ToLower
Dim m_method As String = "POST"
Dim m_type As String = "application/xml"
Dim m_time As String = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ")
Dim m_hashData As String = m_method & vbLf & m_type & vbLf & hashed_content & vbLf & m_time & vbLf & _endPoint_Uri
Dim m_hmac_sha1 As HMAC = New HMACSHA1(Encoding.UTF8.GetBytes(_hmac))
Dim m_hmac_data() As Byte = m_hmac_sha1.ComputeHash(Encoding.UTF8.GetBytes(m_hashData))
Dim m_base64_hash As String = Convert.ToBase64String(m_hmac_data)
Dim httpRequestMessage As HttpRequestMessageProperty
Dim httpRequestMessageObject As Object = Nothing
If request.Properties.TryGetValue(HttpRequestMessageProperty.Name, httpRequestMessageObject) Then
httpRequestMessage = CType(httpRequestMessageObject, HttpRequestMessageProperty)
httpRequestMessage.Headers("x-gge4-date") = m_time
httpRequestMessage.Headers("x-gge4-content-sha1") = hashed_content
httpRequestMessage.Headers("Authorization") = "GGE4_API " & _keyID & ":" & m_base64_hash
Else
httpRequestMessage = New HttpRequestMessageProperty
httpRequestMessage.Headers("x-gge4-date") = m_time
httpRequestMessage.Headers("x-gge4-content-sha1") = hashed_content
httpRequestMessage.Headers("Authorization") = "GGE4_API " & _keyID & ":" & m_base64_hash
request.Properties.Add(HttpRequestMessageProperty.Name, httpRequestMessage)
End If
Return Nothing
End Function
Issue 3:
My Transmit Code, I'm quite sure I got this right this time. I made a Service Reference, and not a web reference this time. I sort of used the same code I used for paypal, but added the endpoint behavior, so the authentication header would be added in the Soap Request.
Using client = New ServiceSoapClient(New BasicHttpsBinding(), remoteAddress)
client.ChannelFactory.Endpoint.EndpointBehaviors.Add(New HMAC_SR_Header_Behavior(
uRequest.eXact.HMAC_ID,
uRequest.eXact.HMAC_Key,
m_endpointUri
)
)
Dim responseType As New TransactionResult
responseType = client.SendAndCommit(ppRequest)
ppResponse = responseType
End Using
FYI:
The FirstData support site was useless. All they do there is mobile stuff, Perl, Ruby, Rest. I got crickets from the site, and deaf ears.
[edited] took my personal information out
modified 30-Jun-15 12:47pm.
|
|
|
|
|
Edited to make XML readable
|
|
|
|
|