Generating msi transform using c# - c#

I am creating a cutomization software which will do all the standardization to a mst file.
Below is the code of class that will change product name and genrate transform.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WindowsInstaller;
using System.Data;
namespace Automation
{
class CustomInstaller
{
public CustomInstaller()
{
}
public Record getInstaller(string msiFile,MsiOpenDatabaseMode mode,string query)
{
Type type = Type.GetTypeFromProgID("WindowsInstaller.Installer");
Installer inst = (Installer)Activator.CreateInstance(type);
Database db = inst.OpenDatabase(msiFile, mode);
WindowsInstaller.View view = db.OpenView(query);
view.Execute(null);
Record record = view.Fetch();
db.Commit();
return record;
}
public bool generateTrans(string file1, string file2,string transName)
{
Type type = Type.GetTypeFromProgID("WindowsInstaller.Installer");
Installer inst = (Installer)Activator.CreateInstance(type);
Database db1 = inst.OpenDatabase(file1, MsiOpenDatabaseMode.msiOpenDatabaseModeReadOnly);
try
{
Database db2 = inst.OpenDatabase(file2, MsiOpenDatabaseMode.msiOpenDatabaseModeReadOnly);
return db2.GenerateTransform(db1, transName);
}
catch (Exception e) { }
return false;
}
public int editTransform(string msiFile, MsiOpenDatabaseMode mode, string query)
{
Type type = Type.GetTypeFromProgID("WindowsInstaller.Installer");
Installer inst = (Installer)Activator.CreateInstance(type);
Database db = inst.OpenDatabase(msiFile, mode);
WindowsInstaller.View view = db.OpenView(query);
view.Execute(null);
db.Commit();
int o=(int)db.DatabaseState;
db = null;
inst = null;
type = null;
return 1;
}
}
}
First editTransform() is called which will create a copy of original msi and do some changes in it, then generateTrans() is called which will get difference detween two msi files and create a transform file.
Now issue is when genrateTrans() is called, then it goes to catch block of it as inst.OpenDatabase return "MSI Api Error".
It seems to me that the copy of file crated by editTransform is still locked by it and is not available for use for generateTrans() menthod.
Please help here.
PS: mode used for edit transform is transact.

Instead of doing the COM Interop, checkout the far superior interop library ( Microsoft.Deployment.WindowsInstaller ) found in Windows Installer XML Deployment Tools Foundation. You'll find it much easier to use.
using System;
using System.IO;
using Microsoft.Deployment.WindowsInstaller;
namespace ConsoleApplication1
{
class Program
{
const string REFERENCEDATABASE = #"C:\orig.msi";
const string TEMPDATABASE = #"C:\temp.msi";
const string TRANSFORM = #"c:\foo.mst";
static void Main(string[] args)
{
File.Copy(REFERENCEDATABASE, TEMPDATABASE, true);
using (var origDatabase = new Database(REFERENCEDATABASE, DatabaseOpenMode.ReadOnly))
{
using (var database = new Database(TEMPDATABASE, DatabaseOpenMode.Direct))
{
database.Execute("Update `Property` Set `Property`.`Value` = 'Test' WHERE `Property`.`Property` = 'ProductName'");
database.GenerateTransform(origDatabase, TRANSFORM);
database.CreateTransformSummaryInfo(origDatabase, TRANSFORM, TransformErrors.None, TransformValidations.None);
}
}
}
}
}

Related

How to generate a hash for my Android app?

I'm using this guide to implement an autocomplete funcionality in an app I'm working on, but when I try to test it in different computers it returns me a different hash https://www.c-sharpcorner.com/article/verify-otp-automatically-in-android-without-sms-read-permission-using-xamarin-fo/
The helper class used is the following:
using System.Text;
using Android.Content;
using Android.Content.PM;
using Android.Util;
using Java.Security;
using Java.Util;
namespace InteliMobile.App.Droid.Service
{
public class AppHashKeyHelper
{
private static string HASH_TYPE = "SHA-256";
private static int NUM_HASHED_BYTES = 9;
private static int NUM_BASE64_CHAR = 11;
private static string GetPackageSignature(Context context)
{
var packageManager = context.PackageManager;
var signatures = packageManager.GetPackageInfo(context.PackageName, PackageInfoFlags.Signatures).Signatures;
return signatures.First().ToCharsString();
}
public static string GetAppHashKey(Context context)
{
string keystoreHexSignature = GetPackageSignature(context);
string appInfo = context.PackageName + " " + keystoreHexSignature;
try
{
var messageDigest = MessageDigest.GetInstance(HASH_TYPE);
messageDigest.Update(Encoding.UTF8.GetBytes(appInfo));
byte[] hashSignature = messageDigest.Digest();
hashSignature = Arrays.CopyOfRange(hashSignature, 0, NUM_HASHED_BYTES);
string base64Hash = Android.Util.Base64.EncodeToString(hashSignature, Base64Flags.NoPadding | Base64Flags.NoWrap);
base64Hash = base64Hash.Substring(0, NUM_BASE64_CHAR);
return base64Hash;
}
catch (NoSuchAlgorithmException e)
{
return null;
}
}
}
}
How can I get the hash without using a bash script, since the server runs in a Windows machine? Is it safe to deploy the app to production with the helper class in it?
You don't compute the hash client side. It's sent from the server, and the instructions to do so are at https://developers.google.com/identity/sms-retriever/verify#computing_your_apps_hash_string
You don't do it in code at all, you do it via command line tools.

VS Xamarin Android SQLite-net crashing the app in Android v7.x

I am trying to make a cross platform app using Visual Studio 2015, Xamarin and SQLite. Everything is working fine until Android v6.0. But, when I test my app in android 7.x (7.0 and 7.1.1) emulators, my app crashed without even starting up. I read on xamarin forum about this crash under these links - Link 1 and Link 2 and came to know that since 7.0 native sqlite can't be used, but the answer there mentioned that -
First I deleted the libraries from 'Manage NuGet Packages for
Solutions...' - library 'sqlite-net-pcl' and the connected one
'SQLitePCL.raw'. Then I installed the new version of through the
PackageManager Console, in my case the command was 'Install-Package
sqlite-net-pcl'. Now the versions are 'sqlite-net-pcl' --> 1.2.0 |
'SQLitePCL.raw' --> 1.0.1. Also it downloaded others dependencies like
SQLitePCLRaw.bundle_green.
But, my project already has the updated version of sqlite-net-pcl and related packages.
sqlite-net-pcl => 1.2.0
SQLitePCL.bundle_green => 0.9.3
SQLitePCL.raw => 0.9.3
SQLitePCLRaw.bundle_green => 1.1.0
SQLitePCLRaw.core => 1.1.0
I am stuck here, they all are updated to the latest what should I change?
Relevant codes -
SqliteService.cs
using System;
using Medical_Study;
using Xamarin.Forms;
using Medical_Study.Droid;
using System.IO;
[assembly: Dependency(typeof(SqliteService))]
namespace Medical_Study.Droid
{
public class SqliteService : ISQLite
{
public SqliteService()
{
}
#region ISQLite implementation
public SQLite.SQLiteConnection GetConnection()
{
var sqliteFilename = "QBank.db";
string documentsPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal); // Documents folder
var path = Path.Combine(documentsPath, sqliteFilename);
// This is where we copy in the prepopulated database
Console.WriteLine(path);
if (!File.Exists(path))
{
var s = Forms.Context.Resources.OpenRawResource(Resource.Raw.QBank); // RESOURCE NAME ###
// create a write stream
FileStream writeStream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write);
// write to the stream
ReadWriteStream(s, writeStream);
}
var conn = new SQLite.SQLiteConnection(path);
// Return the database connection
return conn;
}
#endregion
/// <summary>
/// helper method to get the database out of /raw/ and into the user filesystem
/// </summary>
void ReadWriteStream(Stream readStream, Stream writeStream)
{
int Length = 256;
Byte[] buffer = new Byte[Length];
int bytesRead = readStream.Read(buffer, 0, Length);
// write the required bytes
while (bytesRead > 0)
{
writeStream.Write(buffer, 0, bytesRead);
bytesRead = readStream.Read(buffer, 0, Length);
}
readStream.Close();
writeStream.Close();
}
}
}
DataAccess.cs
using System;
using SQLite;
using System.Collections.Generic;
using System.Linq;
using Xamarin.Forms;
using System.Text;
using System.Threading.Tasks;
using Medical_Study.Models;
namespace Medical_Study
{
public class DataAccess
{
static object locker = new object();
SQLiteConnection database;
public DataAccess()
{
database = DependencyService.Get<ISQLite>().GetConnection();
// create the tables
database.CreateTable<QBank>();
}
public IEnumerable<QBank> GetAllQuestions()
{
lock (locker)
{
return (from i in database.Table<QBank>() select i).ToList();
}
//return database.Query<QBank>("Select * From [QBank] where [qid]");
}
public IEnumerable<QBank> GetSpecialQuestions()
{
lock (locker)
{
return database.Query<QBank>("SELECT * FROM [QBank] WHERE [question_text] = 0");
}
}
public QBank GetQuestion(int id)
{
lock (locker)
{
return database.Table<QBank>().FirstOrDefault(x => x.qid == id);
}
}
public int SaveQuestion(QBank question)
{
lock (locker)
{
if (question.qid != 0)
{
database.Update(question);
return question.qid;
}
else
{
return database.Insert(question);
}
}
}
public int DeleteQuestion(int id)
{
lock (locker)
{
return database.Delete<QBank>(id);
}
}
}
}

Error Connecting To MongoDb from C# .NET Console Application

Unable to connect to server localhost:27017:
No connection could be made because the target machine actively refused it 127.0.0.1:27017.
This exception appears when i run a console application with C# using mongoDB
I've downloaded CSharpDriver-1.4.1.4490.msi
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MongoDB.Bson;
using MongoDB.Driver;
using MongoDB.Driver.Builders;
namespace ConsoleApplication4
{
public class Entity
{
public ObjectId Id { get; set; }
public string Name { get; set; }
}
class Program
{
static void Main(string[] args)
{
var connectionString = "mongodb://localhost:27017";
var server = MongoServer.Create(connectionString);
var database = server.GetDatabase("test");
var collection = database.GetCollection<Entity>("entities");
var entity = new Entity { Name = "Tom" };
collection.Insert(entity);
var id = entity.Id;
var query = Query.EQ("_id", id);
entity = collection.FindOne(query);
entity.Name = "Dick";
collection.Save(entity);
var update = Update.Set("Name", "Harry");
collection.Update(query, update);
collection.Remove(query);
}
}
I would follow the directions here, on the Mongo site. Windows quickstart is a really good resource to get started using Mongo on windows.
As far as connecting to the Mongo instance in .Net, if you didn't do anything special during the installation of Mongo, you shouldn't have to explicitly give a connection string. The following code works for my generic set up of Mongo.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MongoDB.Bson;
using MongoDB.Driver;
using MongoDB.Bson.IO;
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Bson.Serialization.Conventions;
using MongoDB.Bson.Serialization.IdGenerators;
using MongoDB.Bson.Serialization.Options;
using MongoDB.Bson.Serialization.Serializers;
using MongoDB.Driver.Builders;
using MongoDB.Driver.GridFS;
using MongoDB.Driver.Wrappers;
namespace MongoDB
{
class Program
{
static void Main(string[] args)
{
MongoServer server;
MongoDatabase moviesDb;
server = MongoServer.Create();
moviesDb = server.GetDatabase("movies_db");
//Create some data
var movie1 = new Movie { Title = "Indiana Jones and the Raiders of the Lost Ark", Year = "1981" };
movie1.AddActor("Harrison Ford");
movie1.AddActor("Karen Allen");
movie1.AddActor("Paul Freeman");
var movie2 = new Movie { Title = "Star Wars: Episode IV - A New Hope", Year = "1977" };
movie2.AddActor("Mark Hamill");
movie2.AddActor("Harrison Ford");
movie2.AddActor("Carrie Fisher");
var movie3 = new Movie { Title = "Das Boot", Year = "1981" };
movie3.AddActor("Jürgen Prochnow");
movie3.AddActor("Herbert Grönemeyer");
movie3.AddActor("Klaus Wennemann");
//Insert the movies into the movies_collection
var moviesCollection = moviesDb.GetCollection<Movie>("movies_collection");
//moviesCollection.Insert(movie1);
//moviesCollection.Insert(movie2);
//moviesCollection.Insert(movie3);
var query = Query.EQ("Year","1981");
var movieFound = moviesDb.GetCollection<Movie>("movies_collection").Drop();
}
}
}

How to create folder structure in SDL Tridion 2011 SP1 using Core Service

I am using the Core Service on Tridion 2011. I want to create a folder structure, and then create a component in that structure.
Example:
Path of folder structure: /ABCD/DEFG/aaaaa
If the folder exists, we need not create folder. If it doesn't exist we have to create it and create component in it.
I know how to create the component in a folder having URI.
The following is the code I use when I need to Get or Create Folders with SDL Tridion's CoreService. It's a simple recursive method that checks for the existence of the current folder. If it doesn't exist, it goes into GetOrCreate the parent folder and so on until it finds an existing path. On the way out of the recursion, it simply creates the new Folders relative to their immediate parent.
Note: this method does not check the input folderPath. Rather, it assumes it represents a valid path.
private FolderData GetOrCreateFolder(string folderPath, SessionAwareCoreServiceClient client)
{
ReadOptions readOptions = new ReadOptions();
if (client.IsExistingObject(folderPath))
{
return client.Read(folderPath, readOptions) as FolderData;
}
else
{
int lastSlashIdx = folderPath.LastIndexOf("/");
string newFolder = folderPath.Substring(lastSlashIdx + 1);
string parentFolder = folderPath.Substring(0, lastSlashIdx);
FolderData parentFolderData = GetOrCreateFolder(parentFolder, client);
FolderData newFolderData = client.GetDefaultData(ItemType.Folder, parentFolderData.Id) as FolderData;
newFolderData.Title = newFolder;
return client.Save(newFolderData, readOptions) as FolderData;
}
}
I would use IsExistingObject - passing in the WebDAV URL - to see if the Folder already exists. If it returns false, you can go ahead and create the folder.
Edit: Here's some quick pseudo code...
string parentFolderId = #"/webdav/MyPublication/Building%20Blocks";
var client = GetCoreServiceClient();
if (!client.IsExistingObject(parentFolderId + "/AAA"))
{
var folder = client.GetDefaultData(2, parentFolderId);
folder.Title = "AAA";
client.Save(folder);
// Create the other folders and components here
}
This is what we used on one of our projects to create folders for a path.
static FolderData GetOrCreateFolder(List<string> folders,
FolderData root,
SessionAwareCoreService2010Client client)
{
var filter = new OrganizationalItemItemsFilterData();
filter.ItemTypes = new [] { ItemType.Folder };
var items = client.GetListXml(root.Id, filter).
Elements(TRIDION_NAMESPACE + "Item");
foreach (var element in items)
{
if (folders.Count == 0)
{
break; // break from foreach
}
var titleAttribute = element.Attribute("Title");
var idAttribute = element.Attribute("ID");
if (titleAttribute != null && titleAttribute.Value == folders[0] &&
idAttribute != null)
{
// folder exists
FolderData fd = client.Read(idAttribute.Value,
EXPANDED_READ_OPTIONS) as FolderData;
// We just took care of this guy, remove it to recurse
folders.RemoveAt(0);
return GetOrCreateFolder(folders, fd, client);
}
}
if (folders.Count != 0)
{
//Folder doesn't exist, lets create it and return its folderdata
var newfolder = new FolderData();
newfolder.Title = folders[0];
newfolder.LocationInfo = new LocationInfo {
OrganizationalItem = new LinkToOrganizationalItemData {
IdRef = root.Id
}
};
newfolder.Id = "tcm:0-0-0";
var folder = client.Create(newfolder, EXPANDED_READ_OPTIONS)
as FolderData;
folders.RemoveAt(0);
if (folders.Count > 0)
{
folder = GetOrCreateFolder(folders, folder, client);
}
return folder;
}
return root;
}
So you'd invoke it with something like this:
var root = client.Read("tcm:1-1-2", null) as FolderData;
var pathParts = "/ABCD/DEFG/aaaaa".Trim('/').Split('/').ToList();
var folder = GetOrCreateFolder(pathParts, root, client);
For Create a folder use the following code as sample...
You will have to check if the folder exists of course, this code shows how to create a folder within a folder
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CoreWebService.ServiceReference1;
namespace CoreWebService
{
class CoreWebServiceSamples
{
public static void createFolder()
{
string folderWebDavUrl = "/webdav/020%20Content/Building%20Blocks/Content/wstest";
CoreServicesUtil coreServicesUtil = new CoreServicesUtil();
FolderData folderData = coreServicesUtil.getFolderData(folderWebDavUrl);
FolderData folderDataChild = folderData.AddFolderData();
folderDataChild.Title = "childFolder";
folderDataChild = (FolderData)coreServicesUtil.coreServiceClient.Save(folderDataChild, coreServicesUtil.readOptions);
coreServicesUtil.coreServiceClient.Close();
}
}
}
Here is some code for the methods referenced ....
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CoreWebService.ServiceReference1;
using CoreWebService.Properties;
using System.Xml;
using System.Xml.Serialization;
namespace CoreWebService
{
public class CoreServicesUtil
{
public CoreService2010Client coreServiceClient;
public ReadOptions readOptions;
/// <summary>
///
/// </summary>
public CoreServicesUtil()
{
this.coreServiceClient = new CoreService2010Client("basicHttp_2010");
this.readOptions = new ReadOptions();
}
public FolderData getFolderData(string tcmuri)
{
FolderData folderData = (FolderData)coreServiceClient.Read(tcmuri, readOptions);
return folderData;
}
}
public static class CoreServicesItemCreator
{
/**
* <summary>
* Name: AddFolder
* Description: returns a new Folder Data created in the folder Data
* </summary>
**/
public static FolderData AddFolderData(this FolderData folderData)
{
FolderData childFolder = new FolderData();
childFolder.LocationInfo = getLocationInfo(folderData);
childFolder.Id = "tcm:0-0-0";
return childFolder;
}
}
}

MongoDB GridFs with C#, how to store files such as images?

I'm developing a web app with mongodb as my back-end. I'd like to have users upload pictures to their profiles like a linked-in profile pic. I'm using an aspx page with MVC2 and I read that GridFs library is used to store large file types as binaries. I've looked everywhere for clues as how this is done, but mongodb doesn't have any documentation for C# api or GridFs C#. I'm baffled and confused, could really use another set of brains.
Anyone one know how to actually implement a file upload controller that stores an image uploaded by a user into a mongodb collection? Thanks a million!
I've tried variations of this to no avail.
Database db = mongo.getDB("Blog");
GridFile file = new GridFile(db);
file.Create("image.jpg");
var images = db.GetCollection("images");
images.Insert(file.ToDocument());
Following example show how to save file and read back from gridfs(using official mongodb driver):
var server = MongoServer.Create("mongodb://localhost:27020");
var database = server.GetDatabase("tesdb");
var fileName = "D:\\Untitled.png";
var newFileName = "D:\\new_Untitled.png";
using (var fs = new FileStream(fileName, FileMode.Open))
{
var gridFsInfo = database.GridFS.Upload(fs, fileName);
var fileId = gridFsInfo.Id;
ObjectId oid= new ObjectId(fileId);
var file = database.GridFS.FindOne(Query.EQ("_id", oid));
using (var stream = file.OpenRead())
{
var bytes = new byte[stream.Length];
stream.Read(bytes, 0, (int)stream.Length);
using(var newFs = new FileStream(newFileName, FileMode.Create))
{
newFs.Write(bytes, 0, bytes.Length);
}
}
}
Results:
File:
Chunks collection:
Hope this help.
The answers above are soon to be outdated now that the 2.1 RC-0 driver has been released.
The way to work with files in v2.1 MongoDB with GridFS can now be done this way:
using MongoDB.Bson;
using MongoDB.Driver;
using MongoDB.Driver.GridFS;
using System.IO;
using System.Threading.Tasks;
namespace MongoGridFSTest
{
class Program
{
static void Main(string[] args)
{
var client = new MongoClient("mongodb://localhost");
var database = client.GetDatabase("TestDB");
var fs = new GridFSBucket(database);
var id = UploadFile(fs);
DownloadFile(fs, id);
}
private static ObjectId UploadFile(GridFSBucket fs)
{
using (var s = File.OpenRead(#"c:\temp\test.txt"))
{
var t = Task.Run<ObjectId>(() => { return
fs.UploadFromStreamAsync("test.txt", s);
});
return t.Result;
}
}
private static void DownloadFile(GridFSBucket fs, ObjectId id)
{
//This works
var t = fs.DownloadAsBytesByNameAsync("test.txt");
Task.WaitAll(t);
var bytes = t.Result;
//This blows chunks (I think it's a driver bug, I'm using 2.1 RC-0)
var x = fs.DownloadAsBytesAsync(id);
Task.WaitAll(x);
}
}
}
This is taken from a diff on the C# driver tests here
This example will allow you to tie a document to an object
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MongoDB.Driver;
using MongoDB.Driver.Linq;
using MongoDB.Bson;
using MongoDB.Driver.Builders;
using MongoDB.Driver.GridFS;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
MongoServer ms = MongoServer.Create();
string _dbName = "docs";
MongoDatabase md = ms.GetDatabase(_dbName);
if (!md.CollectionExists(_dbName))
{
md.CreateCollection(_dbName);
}
MongoCollection<Doc> _documents = md.GetCollection<Doc>(_dbName);
_documents.RemoveAll();
//add file to GridFS
MongoGridFS gfs = new MongoGridFS(md);
MongoGridFSFileInfo gfsi = gfs.Upload(#"c:\mongodb.rtf");
_documents.Insert(new Doc()
{
DocId = gfsi.Id.AsObjectId,
DocName = #"c:\foo.rtf"
}
);
foreach (Doc item in _documents.FindAll())
{
ObjectId _documentid = new ObjectId(item.DocId.ToString());
MongoGridFSFileInfo _fileInfo = md.GridFS.FindOne(Query.EQ("_id", _documentid));
gfs.Download(item.DocName, _fileInfo);
Console.WriteLine("Downloaded {0}", item.DocName);
Console.WriteLine("DocName {0} dowloaded", item.DocName);
}
Console.ReadKey();
}
}
class Doc
{
public ObjectId Id { get; set; }
public string DocName { get; set; }
public ObjectId DocId { get; set; }
}

Categories