|
There is no such thing as a "local variable which is a reference" in C#, but there is in the underlying MSIL and runtime. That doesn't do you much good, but it might be interesting to know.
|
|
|
|
|
|
My Database Development book includes a program for inserting Images into a database after studying the code and modifying just the connection string and image's directory. When i run the program even with Administrator it produces a Run Time error of "Denied" in the message box. Now the program does connect to the database and does insert values into the Primary Key column and 2 other columns. The problem is that it is not reading the Folder that contains the images and is not inserting them into the database image column.
I have modified the folder's permissions for Full Control but during execution of the software it automatically produces the error message of Denied.The Database has been setup for FILESTREAM and Filestream access level has been modified for level 2 and setup in the Sql Server Properties under FileStream.
Any idea's on what may be causing this issue? I am running Windows 8.1 Pro 64Bit
Class
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.IO;
namespace MusicStoreImageManager
{
class ProductDB
{
static string imagesPath = "C:/Users/Rattlerr/Pictures/Images/";
public static SqlConnection GetConnection()
{
SqlConnection connection = new SqlConnection();
connection.ConnectionString =
"Data Source=RATTLERR;Initial Catalog=Test;Integrated Security=False;User ID=sa;Password=SomePassword";
return connection;
}
public static void WriteImage(int productID, string imageName)
{
SqlConnection connection = null;
SqlTransaction transaction = null;
try
{
string filepath = imagesPath + imageName;
if (File.Exists(filepath) == false)
throw new Exception("File Not Found: " + filepath);
FileStream sourceStream = new FileStream(
filepath,
FileMode.Open,
FileAccess.Read);
connection = GetConnection();
SqlCommand command = new SqlCommand();
command.Connection = connection;
command.CommandText =
"INSERT INTO ProductImages " +
"VALUES (@ProductID, " +
" CAST(@RowID AS uniqueidentifier), 0)";
Guid rowID = Guid.NewGuid();
command.Parameters.AddWithValue("@ProductID", productID);
command.Parameters.AddWithValue("@RowID", rowID);
connection.Open();
command.ExecuteNonQuery();
transaction = connection.BeginTransaction();
command.Transaction = transaction;
command.CommandText =
"SELECT ProductImage.PathName(), " +
" GET_FILESTREAM_TRANSACTION_CONTEXT() " +
"FROM ProductImages " +
"WHERE RowID = CAST(@RowID AS uniqueidentifier)";
command.Parameters.Clear();
command.Parameters.AddWithValue("@RowID", rowID);
SqlDataReader reader = command.ExecuteReader();
if (reader.Read() == false)
throw new Exception("Unable to get path and context for BLOB.");
string path = (string)reader[0];
byte[] context = (byte[])reader[1];
reader.Close();
SqlFileStream targetStream = new SqlFileStream(path, context, FileAccess.Write);
int blockSize = 1024 * 512;
byte[] buffer = new byte[blockSize];
int bytesRead = sourceStream.Read(buffer, 0, buffer.Length);
while (bytesRead > 0)
{
targetStream.Write(buffer, 0, bytesRead);
bytesRead = sourceStream.Read(buffer, 0, buffer.Length);
}
targetStream.Close();
sourceStream.Close();
transaction.Commit();
}
catch (Exception e)
{
if (transaction != null)
transaction.Rollback();
throw e;
}
finally
{
if (connection != null)
connection.Close();
}
}
public static Byte[] ReadImage(int imageID)
{
SqlConnection connection = null;
SqlTransaction transaction = null;
try
{
connection = GetConnection();
connection.Open();
transaction = connection.BeginTransaction();
SqlCommand command = new SqlCommand();
command.Connection = connection;
command.Transaction = transaction;
command.CommandText =
"SELECT ProductImage.PathName(), " +
" GET_FILESTREAM_TRANSACTION_CONTEXT() " +
"FROM ProductImages " +
"WHERE ImageID = @ImageID";
command.Parameters.AddWithValue("@ImageID", imageID);
SqlDataReader reader = command.ExecuteReader();
if (reader.Read() == false)
throw new Exception("Unable to get path and context for BLOB.");
string path = (string)reader[0];
byte[] context = (byte[])reader[1];
reader.Close();
SqlFileStream sourceStream = new SqlFileStream(path, context, FileAccess.Read);
int blockSize = 1024 * 512;
byte[] buffer = new byte[blockSize];
List<byte> imageBytes = new List<byte>();
int bytesRead = sourceStream.Read(buffer, 0, buffer.Length);
while (bytesRead > 0)
{
bytesRead = sourceStream.Read(buffer, 0, buffer.Length);
foreach(byte b in buffer)
imageBytes.Add(b);
}
sourceStream.Close();
return imageBytes.ToArray();
}
catch (Exception e)
{
throw e;
}
finally
{
if (connection != null)
connection.Close();
}
}
public static List<int> GetImageIDList()
{
SqlConnection connection = null;
try
{
connection = GetConnection();
SqlCommand command = new SqlCommand();
command.Connection = connection;
command.CommandText =
"SELECT ImageID FROM ProductImages " +
"ORDER BY ImageID";
connection.Open();
SqlDataReader reader = command.ExecuteReader();
List<int> imageIDList = new List<int>();
while (reader.Read())
{
int imageID = (int)reader[0];
imageIDList.Add(imageID);
}
reader.Close();
return imageIDList;
}
catch (Exception e)
{
throw e;
}
finally
{
if (connection != null)
connection.Close();
}
}
}
}
Main Form Code
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
namespace MusicStoreImageManager
{
public partial class ImageManagerForm : Form
{
public ImageManagerForm()
{
InitializeComponent();
}
private void LoadImageIDComboBox()
{
List<int> imageIDList = ProductDB.GetImageIDList();
foreach (int i in imageIDList)
imageIDComboBox.Items.Add(i);
}
private void ImageManagerForm_Load(object sender, EventArgs e)
{
this.LoadImageIDComboBox();
imageIDComboBox_SelectedIndexChanged(sender, e);
}
private void imageIDComboBox_SelectedIndexChanged(
object sender, EventArgs e)
{
try
{
int imageID = Convert.ToInt32(imageIDComboBox.Text);
Byte[] imageByteArray = ProductDB.ReadImage(imageID);
MemoryStream ms = new MemoryStream(imageByteArray);
imagePictureBox.Image = System.Drawing.Image.FromStream(ms);
ms.Close();
}
catch (Exception ex)
{
MessageBox.Show(this, ex.Message, "Error");
}
}
private void uploadButton_Click(object sender, EventArgs e)
{
try
{
int productID = Convert.ToInt32(productIDTextBox.Text);
string filename = filenameTextBox.Text;
ProductDB.WriteImage(productID, filename);
MessageBox.Show(this, "Image upload was successful!",
"Upload Confirmation");
imageIDComboBox.Items.Clear();
this.LoadImageIDComboBox();
}
catch (Exception ex)
{
MessageBox.Show(this, ex.Message, "Error");
}
}
}
}
modified 3-Jan-15 12:31pm.
|
|
|
|
|
It would help a great deal if you pointed out which line of code is generating the Access Denied message.
The difficult we do right away...
...the impossible takes slightly longer.
|
|
|
|
|
That's the whole problem the code doesn't produce an error or warnings during Debug or compilation just at Run time the error message pops up in a Message Box. The program is suppose to read the folder and load the image into the Image Picture Box nor will it upload the image to the database. The image column just shows 0x0000000 that is because none of the images are being loaded into the Image column for the table.
It will put information into the other columns just not the image, I cannot figure out if it is a permissions issue. Now when i select a different ImageID from the dropdown box the error will repeat itself here is the code below.
private void imageIDComboBox_SelectedIndexChanged(
object sender, EventArgs e)
{
try
{
int imageID = Convert.ToInt32(imageIDComboBox.Text);
Byte[] imageByteArray = ProductDB.ReadImage(imageID);
MemoryStream ms = new MemoryStream(imageByteArray);
imagePictureBox.Image = System.Drawing.Image.FromStream(ms);
ms.Close();
}
catch (Exception ex)
{
MessageBox.Show(this, ex.Message, "Error");
}
}
modified 31-Dec-14 17:34pm.
|
|
|
|
|
What you say makes no sense. "Debug" is runtime, is it not? You're running the program in the debugger, right?
The difficult we do right away...
...the impossible takes slightly longer.
|
|
|
|
|
Doesn't matter if i run it in the debugger or the compiled executable the same error repeats itself. I have modified the folder permissions to full control and even tried running the program under administrative privileges.
|
|
|
|
|
OK I think I understand what you mean. You mean the program is not breaking with an unhandled exception.
One big problem with your code is that you have so many different operations all encompassed within single try/catch blocks that it's hard to tell where the exception is coming from.
If you were to temporarily comment out the try/catch blocks, but leave the code they contain, then the exception will become plain.
The difficult we do right away...
...the impossible takes slightly longer.
|
|
|
|
|
I will try that this code is not mine it was written by the author of the book murachs Sql Server 2012 for Developers. When i run the Debugger a message box pops up and says Error "Access is Denied". If i press the Okay button the program continues and loads the main form but the picture box is empty because the image columns are empty.
Now if i enter a productID into the textbox and press the upload button it will insert the productID into the productID column and generate a ImageID and RowID. The program is setup to look in the images folder, you type the image name for example "picture.jpg" into the textbox put in the productID number into the textbox and press the upload button.
static string imagesPath = "C:/Users/Gerry/Pictures/Images/";
modified 31-Dec-14 17:57pm.
|
|
|
|
|
Well, finding out exactly which line of code is causing the exception is the first step to solving the problem.
Could it be that the path you point out does not exist on your machine?
The difficult we do right away...
...the impossible takes slightly longer.
|
|
|
|
|
The path does exist for the fact that i created the folder and set the permissions to full control. Now i am starting to think it might be a database permissions issue even thou it does connect to the database under the SA user role for authentication. The connection string works just fine i have another program that will log in and retrieve data from the database and load it into a DataGrid. Below is the TSQL i used to create the Database and FILESTREAM and I made sure the FILESTREAM is turned on under the SQL Server Configuration Manager.
CREATE DATABASE medical
ON PRIMARY
(
NAME = medical,
FILENAME = 'C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\DATA\medical.mdf'),
FILEGROUP FileSteamImages CONTAINS FILESTREAM DEFAULT
(
NAME = medicalImages,
FILENAME = 'C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\DATA\medical_images');
GO
Here is the code i used to elevate the permissions:
EXEC sp_configure filestream_access_level, 2;
RECONFIGURE;
|
|
|
|
|
rattlerrFx wrote: Now i am starting to think it might be a database permissions issue
There's no use making a guess. Try doing what I said, and you'll find out exactly what's wrong.
The difficult we do right away...
...the impossible takes slightly longer.
|
|
|
|
|
No luck i commented out every try and catch block in the entire program still generates the same error. I think the error is being generated by the SQL Server.
|
|
|
|
|
I find that hard to believe since the function that's generating the messagebox is itself inside a catch block. Are you sure you commented out every try/catch block?
The difficult we do right away...
...the impossible takes slightly longer.
|
|
|
|
|
Now if i comment out just the Try and Catch in the following code the program does not produce the error but it also will not continue to load the program the debugger stops.
private void imageIDComboBox_SelectedIndexChanged(
object sender, EventArgs e)
{
int imageID = Convert.ToInt32(imageIDComboBox.Text);
Byte[] imageByteArray = ProductDB.ReadImage(imageID);
MemoryStream ms = new MemoryStream(imageByteArray);
imagePictureBox.Image = System.Drawing.Image.FromStream(ms);
ms.Close();
}
|
|
|
|
|
And when the program does not continue to load, what happens? Does it break with an unhandled exception?
The difficult we do right away...
...the impossible takes slightly longer.
|
|
|
|
|
It does not break or report any exceptions the debugger stops after about 6 secs.
|
|
|
|
|
SqlFileStream sourceStream = new SqlFileStream(path, context, FileAccess.Read);
System.ComponentModel.Win32Exception occurred
HResult=-2147467259
Message=Access is denied
Source=System.Data
ErrorCode=-2147467259
NativeErrorCode=5
StackTrace:
at System.Data.SqlTypes.SqlFileStream.OpenSqlFileStream(String path, Byte[] transactionContext, FileAccess access, FileOptions options, Int64 allocationSize)
at System.Data.SqlTypes.SqlFileStream..ctor(String path, Byte[] transactionContext, FileAccess access, FileOptions options, Int64 allocationSize)
at System.Data.SqlTypes.SqlFileStream..ctor(String path, Byte[] transactionContext, FileAccess access)
at MusicStoreImageManager.ProductDB.ReadImage(Int32 imageID) in c:\Users\Gerry\Downloads\sq12_allfiles\SQL Server 2012\Projects\C#\Chapter 20b\MusicStoreImageManager\ProductDB.cs:line 132
InnerException:
|
|
|
|
|
Turn on first chance exceptions and the debugger will break at the correct spot whether you have try/catch blocks or not. Then examine the *original* exception to get the real error message and line number.
|
|
|
|
|
That showed me the issue:
SqlFileStream sourceStream = new SqlFileStream(path, context, FileAccess.Read);
System.ComponentModel.Win32Exception occurred
HResult=-2147467259
Message=Access is denied
Source=System.Data
ErrorCode=-2147467259
NativeErrorCode=5
StackTrace:
at System.Data.SqlTypes.SqlFileStream.OpenSqlFileStream(String path, Byte[] transactionContext, FileAccess access, FileOptions options, Int64 allocationSize)
at System.Data.SqlTypes.SqlFileStream..ctor(String path, Byte[] transactionContext, FileAccess access, FileOptions options, Int64 allocationSize)
at System.Data.SqlTypes.SqlFileStream..ctor(String path, Byte[] transactionContext, FileAccess access)
at MusicStoreImageManager.ProductDB.ReadImage(Int32 imageID) in c:\Users\Gerry\Downloads\sq12_allfiles\SQL Server 2012\Projects\C#\Chapter 20b\MusicStoreImageManager\ProductDB.cs:line 132
InnerException:
|
|
|
|
|
OK, according to the docs, SqlFileStream requires integrated security. SQL server authentication is not supported.
|
|
|
|
|
Thank You for the Help it is greatly appreciated..
Modified the connection string a new error is produced:
imagePictureBox.Image = System.Drawing.Image.FromStream(ms);
System.ArgumentException occurred
HResult=-2147024809
Message=Parameter is not valid.
Source=System.Drawing
StackTrace:
at System.Drawing.Image.FromStream(Stream stream, Boolean useEmbeddedColorManagement, Boolean validateImageData)
at System.Drawing.Image.FromStream(Stream stream)
at MusicStoreImageManager.ImageManagerForm.imageIDComboBox_SelectedIndexChanged(Object sender, EventArgs e) in c:\Users\Gerry\Downloads\sq12_allfiles\SQL Server 2012\Projects\C#\Chapter 20b\MusicStoreImageManager\ImageManagerForm.cs:line 45
InnerException:
|
|
|
|
|
That's on the reading side, correct? Is the image correctly inserted into the database now?
|
|
|
|
|
No, it is located below the part i have in Bold and Italic is what produces the error. If i go to the debugger and select Continue it will continue to load the form and have an successful upload to the database.
private void imageIDComboBox_SelectedIndexChanged(
object sender, EventArgs e)
{
try
{
int imageID = Convert.ToInt32(imageIDComboBox.Text);
Byte[] imageByteArray = ProductDB.ReadImage(imageID);
MemoryStream ms = new MemoryStream(imageByteArray);
imagePictureBox.Image = System.Drawing.Image.FromStream(ms);
ms.Close();
}
catch (Exception ex)
{
MessageBox.Show(this, ex.Message, "Error");
}
}
System.ArgumentException occurred
HResult=-2147024809
Message=Parameter is not valid.
Source=System.Drawing
StackTrace:
at System.Drawing.Image.FromStream(Stream stream, Boolean useEmbeddedColorManagement, Boolean validateImageData)
at System.Drawing.Image.FromStream(Stream stream)
at MusicStoreImageManager.ImageManagerForm.imageIDComboBox_SelectedIndexChanged(Object sender, EventArgs e) in c:\Users\Gerry\Downloads\sq12_allfiles\SQL Server 2012\Projects\C#\Chapter 20b\MusicStoreImageManager\ImageManagerForm.cs:line 45
InnerException:
|
|
|
|
|
So you just need to turn off first chance exceptions. Some areas of .Net work based on exceptions (i.e. serialization) and they are handled by the framework. Remember, the first chance exceptions let you catch exceptions before the try / catch does. You shouldn't normally run with them on.
|
|
|
|