How to use SqlFileStream for transactional access to SQL Server 2012 FileTable? - sql

I'm trying to use the SqlFileStream object in a WCF service to get a handle to a specific file that is in a SQL Server 2012 FileTable. I'm able to get the path and transaction context like you would expect with no issues using this piece of code:
using (SqlConnection con2 = new SqlConnection(ConfigurationManager.ConnectionStrings["FileStorage"].ConnectionString))
{
con2.Open();
string getFileHandleQuery = String.Format(
#"SELECT FileTableRootPath(), file_stream.GetFileNamespacePath(), GET_FILESTREAM_TRANSACTION_CONTEXT()
FROM {0}
WHERE stream_id = #streamId", "FSStore");
byte[] serverTransactionContext;
string serverPath;
using (SqlCommand sqlCommand = new SqlCommand(getFileHandleQuery, con2))
{
sqlCommand.Parameters.Add("#streamId", SqlDbType.UniqueIdentifier).Value = new Guid(finalFileHandleStreamId);
using (SqlDataReader sqlDataReader = sqlCommand.ExecuteReader())
{
sqlDataReader.Read();
serverPath = String.Concat(sqlDataReader.GetSqlString(0).Value, sqlDataReader.GetSqlString(1).Value);
serverTransactionContext = sqlDataReader.GetSqlBinary(2).Value;
sqlDataReader.Close();
}
}
con2.Close();
}
However, once I try and actually use the path and transaction context to create a new SqlFileStream:
using (SqlFileStream dest =
new SqlFileStream(serverPath, serverTxn, FileAccess.Write))
{
...
}
The above blows ups with the following exception: The mounted file system does not support extended attributes.
Can someone please explain to me what I'm doing wrong here?
Thanks!

If you are trying to use FileTable and receive an error when new a SqlFileStream object, please check the filePath value.
SqlFileStream sfs = new SqlFileStream(filePath, objContext, System.IO.FileAccess.Read); <-- Error "The mounted file system does not support extended attributes"
Correct way to obtain the filePath value is
SELECT [file_stream].PathName() FROM dbo.fTable WHERE name = 'test.xlsx'
filePath value should look like:
\\HOSTNAME\MSSQLSERVER\v02-A60EC2F8-2B24-11DF-9CC3-AF2E56D89593\test\dbo\fTable\file_stream\A654465D-1D9F-E311-B680-00155D98CA00\VolumeHint-HarddiskVolume1
not like:
\\HOSTNAME\MSSQLSERVER\Store\fDirectory\test.xlsx
That is required by design. Please refer to
https://connect.microsoft.com/SQLServer/feedback/details/729273/sql-server-denali-filetable-access-using-sqlfilestream-returns-error-the-mounted-file-system-does-not-support-extended-attributes
and
Access FILESTREAM Data with OpenSqlFilestream
http://technet.microsoft.com/en-us/library/bb933972.aspx

Related

SSRS Report executes directly but WCF ReportExporter.Export method returns null Result and no errors

I have a report that is hosted in SQL Server 2012 SSRS and it executes fine through the browser. I am trying to run it using WCF as a Service Reference for the SSRS 2005 asmx from a ASP.Net web project and return it as a PDF using the ReportExporter.Export() method; however, it is not returning a result at all and the warnings array is empty. So, how can I troubleshoot the process to see where the difficulty is? I did not find any errors in the SSRS Log file even when I set it to verbose; nor did I find any errors in the standard SQL Log.
Here is my code:
NOTE: the call ReportExporter.Export(..) is to a method that encapsulates the execution of the webServiceProxy to the Service Reference.
{
IList<SSRS_Reports.ParameterValue> parameters = new List<SSRS_Reports.ParameterValue>();
parameters.Add(new SSRS_Reports.ParameterValue { Name = "paramId", Value = _paramId.ToString() }); }
byte[] result = null;
string extension = string.Empty;
string mimeType = string.Empty;
string encoding = string.Empty;
string reportName = "/baseFolder/ReceiptReport";
SSRS_Reports.Warning[] warnings = null;
string[] streamIDs = null;
string uN = ConfigurationManager.AppSettings["rptUName"].ToString();
string uP = ConfigurationManager.AppSettings["rptPWD"].ToString();
string uD = ConfigurationManager.AppSettings["rptDomain"].ToString();
//NOTE: the call "ReportExporter.Export(..) is to a method that encapsulates the execution of the webServiceProxy to the Service Reference.
ReportExporter.Export("ReportExecutionServiceSoap",
new System.Net.NetworkCredential(uN, uP, uD),
reportName,
parameters.ToArray(),
ExportFormat.PDF,
out result,
out extension,
out mimeType,
out encoding,
out warnings,
out streamIDs);
if (result != null)
{
//create a file and then show in browser
_mPDFFile = randomName() + ".pdf";
_mPDFPath = HttpRuntime.AppDomainAppPath + "\\pdf\\" + _mPDFFile;
//clear files older than today
Lib.FileManager.ManageFiles(HttpRuntime.AppDomainAppPath + "\\pdf", "*.pdf", -1);
if (File.Exists(_mPDFPath))
{
File.Delete(_mPDFPath);
}
FileStream stream = File.Create(_mPDFPath, result.Length);
stream.Write(result, 0, result.Length);
stream.Close();
return true;
}
}

Set Crystal Reports Jet database password programmatically

I don't know how to programmatically create Crystal Reports OLE DB (ADO) connection with provider Microsoft Office 12.0 Access Database Engine like what I did in this image
OLE DB (ADO)
I need to specify Jet Database password programmatically Jet Database Password
Note : when I use
Dim reportDocument As New ReportDocument()
reportDocument.Load(" MY REPORT PATH ")
reportDocument.SetDatabaseLogon("Admin","Password")
this method sets password from "Jet Database Password" image ... I don't need to set password I need to set Jet database password
I am using following code to pass the jet database password using crystal reports 13 API: (m_repDoc is the report object)
TableLogOnInfo logonInfo = new TableLogOnInfo();
foreach (Table table in m_repDoc.Database.Tables)
{
logonInfo = table.LogOnInfo;
logonInfo.ConnectionInfo.ServerName = server; // path to database file
logonInfo.ConnectionInfo.LogonProperties.Add(new NameValuePair2(
"Jet OLEDB:Database Password", password)); // Your jet database password
table.ApplyLogOnInfo(logonInfo);
}
Of course this is written nowhere in the manuals/help files. It should also work if you are using subreports.
try
{
ReportDocument r = new ReportDocument();
r.Load(path + rptname);
CrystalDecisions.ReportAppServer.ClientDoc.ISCDReportClientDocument boReportClientDocument;
CrystalDecisions.ReportAppServer.DataDefModel.Database boDatabase;
CrystalDecisions.ReportAppServer.DataDefModel.Tables boTables;
CrystalDecisions.ReportAppServer.Controllers.DatabaseController boDatabaseController;
CrystalDecisions.ReportAppServer.DataDefModel.ConnectionInfo boConnectionInfo;
CrystalDecisions.ReportAppServer.DataDefModel.PropertyBag boAttributesPropertyBag;
CrystalDecisions.ReportAppServer.DataDefModel.PropertyBag boLogonPropertyBag;
boReportClientDocument = r.ReportClientDocument;
boDatabaseController = boReportClientDocument.DatabaseController;
boDatabase = boDatabaseController.Database;
boTables = boDatabase.Tables;
foreach (CrystalDecisions.ReportAppServer.DataDefModel.ISCRTable boTableOld in boTables)
{
CrystalDecisions.ReportAppServer.DataDefModel.ISCRTable boTableNew = boTableOld.Clone(true);
boConnectionInfo = boTableNew.ConnectionInfo;
boAttributesPropertyBag = (CrystalDecisions.ReportAppServer.DataDefModel.PropertyBag)boConnectionInfo.Attributes;
// Change the attributes and QE_LogonProperties to an ODBC connection
boAttributesPropertyBag["QE_ServerDescription"] = dbpath;
boLogonPropertyBag = (CrystalDecisions.ReportAppServer.DataDefModel.PropertyBag)boAttributesPropertyBag["QE_LogonProperties"];
boLogonPropertyBag["Data Source"] = dbpath;
boLogonPropertyBag["Jet Database Password"] = "54321";
boAttributesPropertyBag = (CrystalDecisions.ReportAppServer.DataDefModel.PropertyBag)boConnectionInfo.Attributes;
boTableNew.QualifiedName = boTableNew.Name;
boTableNew.ConnectionInfo.UserName = "Admin";
boTableNew.ConnectionInfo.Password = "";
boDatabaseController.SetTableLocation(boTableOld, boTableNew);
}
r.VerifyDatabase();
crystalReportViewer1.ReportSource = r;
crystalReportViewer1.Refresh();
}
catch (Exception ex) { MessageBox.Show(ex.ToString()); }
you can add it to your App or Web config as keys like:
<add key="ServerName" value="YourServer"/>
<add key="DataBaseName" value="WorkingDataBase"/>
<add key="DatabaseUser" value="DBUser"/>
<add key="DatabasePassword" value="DBPassword"/>
and call them in your code like:
Dim SERVER_NAME As String = ConfigurationManager.AppSettings("ServerName").ToString()
Dim DATABASE_NAME As String = ConfigurationManager.AppSettings("DataBaseName").ToString()
Dim DatabaseUser As String = ConfigurationManager.AppSettings("DatabaseUser").ToString()
Dim DatabasePassword As String = ConfigurationManager.AppSettings("DatabasePassword").ToString()
and for security issue you can encrypt the password and decrypt it.

remote process with wmi, get return value

the following code connects to a remote pc and execute the process try.exe located on that pc.
string prcToRun = "\"C:\\try.exe\" \"";;
object[] theProcessToRun = { prcToRun };
ConnectionOptions theConnection = new ConnectionOptions();
theConnection.Username = "domain\\user";
theConnection.Password = "password.";
ManagementScope theScope = new ManagementScope("\\\\192.168.1.1\\root\\cimv2", theConnection);
ManagementClass theClass = new ManagementClass(theScope, new ManagementPath("Win32_Process"), new ObjectGetOptions());
theScope.Connect();
theClass.InvokeMethod("Create", theProcessToRun);
It works fine, because "try.exe" does what I expect. However I'd like to obtain back the result of try.exe execution. Is it possibile with wmi? At least I need to know when try.exe ends, but it would be better return a value. I know it would be possibile with psexec, but I can't use it.
Thank you

Accessing UniData through .net

I'm having trouble with accessing UniData data from the u2.net toolkit. I'm able to connect ok - have tested connections with the "Test Connection Tool" and in code, both connections work fine. My problem is when I try and fill a dataset - using the sample code: I get this error:
[U2][UCINET][UNIDATA]:You have no privilege on file THENAME
Here is the code:
U2Connection con = new U2Connection();
try
{
U2ConnectionStringBuilder conn_str = new U2ConnectionStringBuilder();
conn_str.UserID = "id";
conn_str.Password = "pwd";
conn_str.Server = "srv2";
conn_str.Database = "DB.XXX";
conn_str.ServerType = "UNIDATA";
conn_str.RpcServiceType = "udserver";
con.ConnectionString = conn_str.ToString();
con.Open();
DataTable schema = con.GetSchema();
U2DataAdapter da = new U2DataAdapter("SELECT * FROM THENAME ", con);
DataSet ds = new DataSet();
da.Fill(ds);
}
catch (Exception ex)
{
string lStr = ex.Message;
}
finally
{
con.Close();
1 more note, I have an ODBC connection setup. Through ODBC I can use the same credentials inside a SQL Server Linked Server to access the same query successfully.
Any Ideas would be appreciated.
By default, UniData grants no privileges to access files via SQL.
You will need to run CONVERT.SQL from the database to grant privileges to the file.
You can find out more about the command by either running HELP CONVERT.SQL on the command line, or reading the manuals.
Could you please run TCL command ?
select * from privilege;
Do you see THENAME there? For example, see enclosed screen shot for VOC file.

How do I programmatically tell if a client machine has the Microsoft.Jet.OLEDB.4.0 as a valid provider?

I need to export data into an Access database. My code works, but it works with the assumption the client machine has the Microsoft.Jet.OLEDB.4.0 as a valid provider.
I want to test to see if this is true or not, in code. My problem is that I don't have the location of an existing access database and I don't want to create a new .mdb that I'd use to verify the connection and then delete it.
Is there any way to tell which providers are installed?
You could simply check for the existence of
HKEY_CLASSES_ROOT\CLSID\{dee35070-506b-11cf-b1aa-00aa00b8de95}
which is the CLSID of Microsoft.Jet.OLEDB.4.0.
you could try to detect the MDAC version on the machine and based on that extrapolate if your provider is supported?
http://www.planetsourcecode.com/vb/scripts/ShowCode.asp?txtCodeId=47262&lngWId=1
here's a snippet you can take a look at.
Each major provider has classid mentioned under the registry editor
Ex:-
HKEY_CLASSES_ROOT\CLSID{dee35070-506b-11cf-b1aa-00aa00b8de95}
which is the CLSID of Microsoft.Jet.OLEDB.4.0.
To check programmatically, use below c# code, its checked on framework 2.0
using System.Data.OleDb;
OleDbEnumerator enumerator = new OleDbEnumerator();
DataTable table = enumerator.GetElements();
bool bNameFound = false;
bool bCLSIDFound = false;
foreach (DataRow row in table.Rows)
{
foreach (DataColumn col in table.Columns)
{
if ((col.ColumnName.Contains("SOURCES_CLSID")) && (row[col].ToString().Contains("{dee35070-506b-11cf-b1aa-00aa00b8de95}")))
Console.WriteLine("CLSID of Microsoft.Jet.OLEDB.4.0. Found");
if ((col.ColumnName.Contains("SOURCES_NAME")) && (row[col].ToString().Contains("Microsoft.ACE.OLEDB.12.0")))
{
bNameFound = true;
if ((col.ColumnName.Contains("SOURCES_CLSID")) && (row[col].ToString().Contains("{3BE786A0-0366-4F5C-9434-25CF162E475E}")))
bCLSIDFound = true;
}
}
}
if (!bNameFound && !bCLSIDFound)
Console.WriteLine("Microsoft.ACE.OLEDB.12.0 Not found");
else
Console.WriteLine("Microsoft.ACE.OLEDB.12.0 found");
Remember "Fix it right & not let the test bugs bite"
I believe if you have the .NET Framework installed (needed to run VB.NET Code) then the machine has the provider you mention. MSDN
Dim reader As Object = OleDbEnumerator.GetRootEnumerator()
Dim Oleprovide As String = ""
While reader.Read
For i = 0 To reader.FieldCount - 1
If reader.GetName(i) = "SOURCES_NAME" Then
If reader.GetValue(i).ToString.Contains(".OLEDB.") = True Then
Oleprovide = reader.GetValue(i).ToString
Exit For
End If
End If
Next
End While
reader.Close()
Dim MyConnection As OleDbConnection
MyConnection = New OleDbConnection("Provider=" & Oleprovide & ";Data Source=" & existingFile.FullName & ";Extended Properties=""Excel 13.0 Xml;HDR=Yes""")
MyConnection.Open()