I've been trying to write a simple little Cmdlet to allow me to Set/Get/Remove cache items. The problem I have is that I cannot figure out how to connect to the local cache cluster.
I've tried adding in the usual app.config stuff, but that doesn't seem to get picked up ...
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="dataCacheClient" type="Microsoft.ApplicationServer.Caching.DataCacheClientSection, Microsoft.ApplicationServer.Caching.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" allowLocation="true" allowDefinition="Everywhere" />
</configSections>
<dataCacheClient>
<hosts>
<host name="localhost" cachePort="22233" />
</hosts>
</dataCacheClient>
</configuration>
I'd rather not have that config at all. So what I am really asking is what the equivalent C# code is for the following powershell...
Use-CacheCluster
From what I can gather Use-CacheCluster connect to the local cluster if no parameters are supplied
I've just done some spelunking into the AppFabric Powershell code with Reflector to see how it works under the covers. If you call Use-CacheCluster with no parameters e.g. for the local cluster, the code reads the connection string and provider name from the Registry key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\AppFabric\V1.0\Configuration. Unfortunately, it then uses those values to build a series of classes (ClusterConfigElement, CacheAdmin and ClusterHandler) which are all marked as internal, so you can't use them to pick up the current cluster context (for want of a better word) that Powershell is working with.
To make your Cmdlet work, then, I think you need to pass in a hostname (which would be one of the servers in your cluster, and perhaps you could default this to the local machine name) and a port number (which you could default to 22233), and use those values to build a DataCacheServerEndpoint to pass to your DataCacheFactory e.g.
[Cmdlet(VerbsCommon.Set,"Value")]
public class SetValueCommand : Cmdlet
{
[Parameter]
public string Hostname { get; set; }
[Parameter]
public int PortNumber { get; set; }
[Parameter(Mandatory = true)]
public string CacheName { get; set; }
protected override void ProcessRecord()
{
base.ProcessRecord();
// Read the incoming parameters and default to the local machine and port 22233
string host = string.IsNullOrWhiteSpace(Hostname) ? Environment.MachineName : Hostname;
int port = PortNumber == 0 ? 22233 : PortNumber;
// Create an endpoint based on the parameters
DataCacheServerEndpoint endpoint = new DataCacheServerEndpoint(host, port);
// Create a config using the endpoint
DataCacheFactoryConfiguration config = new DataCacheFactoryConfiguration();
config.Servers = new List<DataCacheServerEndpoint> { endpoint };
// Create a factory using the config
DataCacheFactory factory = new DataCacheFactory(config);
// Get a reference to the cache so we can now start doing useful work...
DataCache cache = factory.GetCache(CacheName);
...
}
}
The problem is that the call:
DataCacheFactoryConfiguration config = new DataCacheFactoryConfiguration();
inside Cmdlet mothods produces an error sounding like "Cannot initialize DataCacheFactoryConfiguration".
Related
So I'm trying to deploy a database on Azure using EF code first. I have one model:
public class User
{
[Key]
public int PersonID { get; set; }
[Required(ErrorMessage = "A first name is required.")]
[StringLength(20, MinimumLength = 2, ErrorMessage = "Your firstname needs to be atleast 2 letters long")]
[RegularExpression(#"^[a-zA-Z]*$", ErrorMessage = "Your firstname can only contain letters")]
[Display(Name = "First Name:")]
public string FirstName { get; set; }
}
DataContext-class:
public class DataContext : DbContext
{
public DataContext() : base("DataContext")
{
}
public DbSet<User> User { get; set; }
}
DataContextInitalizer-class:
public class DataContextInitializer : DropCreateDatabaseIfModelChanges<DataContext>
{
}
In the global.asax-file to initalize the datacontext:
Database.SetInitializer(new DataContextInitializer());
And then finally the string to connect to the database in the web.config:
<connectionStrings>
<add name="DataContext" connectionString="Data Source=tcp:*.database.windows.net,1433;Initial Catalog=TestApi20180311012458_db;User ID=usernamehere;Password=passwordhere" providerName="System.Data.SqlClient" />
Thou no tables are created when building the solution. I dont know where I'm missing out. Can you see whats wrong?
Thou no tables are created when building the solution. I dont know where I'm missing out. Can you see whats wrong?
Your code just to connect Azure sql in your local project. And the data initialization just uses to initialize data in table. But your tables have not created yet. If you want to create table in Azure sql, you could use Migrations.
Azure sql connection string in web.config:
<connectionStrings>
<add name="ConnectionStringName" providerName="System.Data.SqlClient" connectionString="Data Source=tcp:[databasename].database.windows.net,1433;Initial Catalog=[databasename];Integrated Security=False;User Id=[username];Password=[password];Encrypt=True;TrustServerCertificate=False;MultipleActiveResultSets=True" />
</connectionStrings>
Open Tools> Nuget Mackage Manager>Package Manager Console. Then enter the following code:
Enable-migrations
Add-migration initial
update-database
After that, you could see the tables are created in Azure Sql.
For another way, you could use publish tool to connect to Azure sql and use Code First Migrations automatically. Do not need to use code to configure manually. Open Publish settings to configure Azure sql. Or you could read this article to learn more details.
I have coded like the below:
#Code
DatabaseProviderFactory factory = new DatabaseProviderFactory();
database = factory.Create("DBinstanceName");
ConfigFile Entries
<oracleConnectionSettings>
<add name="CNQ" />
</oracleConnectionSettings>
<connectionStrings>
<add name="CNQ" connectionString=" Min Pool Size=0;Connection Lifetime=120;Max Pool Size=50; Data Source=(DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST= XXXX.com)(PORT=1521))) (CONNECT_DATA = (SID = cnq) (SERVER = DEDICATED) ) );"
providerName="Oracle.DataAccess.Client" />
</connectionStrings>
With the above code and config settings, the DatabaseObject is created perfectly. When I verify the connectionstring it has the values what I had mentioned in the connnection string. So far good.
Now, I have to add the UserId & Password to the connection string at the runtime. There is no methods I could find to add the user credentials to the existing connection string. Becuase, in the Database object the connection string is READ ONLY.
The only way I find is to set in the configuration file[App.config], which is not the way we want, because for every user, we have a separate userid and password in the Oracle database.
In fact, I had tried by settings the connections at the command object, and passed the command object to the execute reader, even then also the enterprise library 6.0, not taking the connection we set in the command object.
Please help us how to set the userid and password in the runtime.
Thanks in advance
In order to set connection string values at runtime you will have to programmatically create your database objects. For example:
Database database = new GenericDatabase(GetConnectionString(),
DbProviderFactories.GetFactory("Oracle.DataAccess.Client"));
Or if you are using OracleDatabase something like:
OracleDatabase database = new OracleDatabase(GetConnectionString());
You could use extension methods to hide a bit of the ugliness:
DatabaseProviderFactory factory = new DatabaseProviderFactory();
Database db = factory.CreateWithConnectionString(GetConnectionString(),
DbProviderFactories.GetFactory("Oracle.DataAccess.Client"));
db = factory.CreateOracleDatabase(GetConnectionString());
public static class DatabaseProviderFactoryExtensions
{
public static Database CreateWithConnectionString(this DatabaseProviderFactory factory,
string connectionString,
DbProviderFactory dbProviderFactory)
{
return new GenericDatabase(connectionString, dbProviderFactory);
}
public static Database CreateOracleDatabase(this DatabaseProviderFactory factory,
string connectionString)
{
return new OracleDatabase(connectionString);
}
}
Another way to approach the issue if you know what connections you will have in advance (still at runtime but perhaps at application startup) is to use the DatabaseFactory.SetDatabases method to return the correct database based on a key. Unfortunately, the method only takes a single string so you can't specify nicely the username and password but you might be able to do something like this:
DatabaseFactory.SetDatabases(() => GetDatabase("Default"),
(dbName) => GetDatabase(dbName));
Database db = DatabaseFactory.CreateDatabase();
public Database GetDatabase(string dbName)
{
string connectionString = GetConnectionString(dbName);
return new OracleDatabase(connectionString);
}
Where the GetConnectionString method can create the proper connection string based on a name. However, I'm guessing this last way might not be the best given your description.
Thanks for your response.
Because I am using the Enterprise Library 6.0, only the First answer only works.
Database database = new GenericDatabase(GetConnectionString(),
DbProviderFactories.GetFactory("Oracle.DataAccess.Client"));
[or]
Oralce.DataAccess.Client.OralceClientFactory ocf = new Oracle.DataAccess.Client.OracleClientFactory();
Database database = new GenericDatabase(GetConnectionString(), ocf);
Thanks
Using WCF Data Services (and the latest Entity Framework), I want to return data from a stored procedure. The returned sproc fields do not match 1:1 any entity in my db, so I create a new complex type for it in the edmx model (rather than attaching an existing entity):
Right-click the *.edmx model / Add / Function Import
Select the sproc (returns three fields) - GetData
Click Get Column Information
Add the Function Import Name: GetData
Click Create new Complex Type - GetData_Result
In the service, I define:
[WebGet]
public List<GetData_Result> GetDataSproc()
{
PrimaryDBContext context = new PrimaryDBContext();
return context.GetData().ToList();
}
I created a quick console app to test, and added a reference to System.Data.Services and System.Data.Services.Client - this after running Install-Package EntityFramework -Pre, but the versions on the libraries are 4.0 and not 5.x.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Services.Client;
using ConsoleApplication1.PrimaryDBService;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
DataServiceContext context = new DataServiceContext(new Uri("http://localhost:50100/PrimaryDataService1.svc/"));
IEnumerable<GetData_Result> result = context.Execute<GetData_Result>(new Uri("http://localhost:50100/PrimaryDataService1.svc/GetDataSproc"));
foreach (GetData_Result w in result)
{
Console.WriteLine(w.ID + "\t" + w.WHO_TYPE_NAME + "\t" + w.CREATED_DATE);
}
Console.Read();
}
}
}
I didn't use the UriKind.Relative or anything else to complicate this.
When I navigate in the browser to the URL, I see data, but when I consume it in my console app, I get nothing at all.
Adding tracing to the mix:
<system.diagnostics>
<sources>
<source name="System.ServiceModel" switchValue="Information, ActivityTracing" propagateActivity="true">
<listeners>
<add name="traceListener" type="System.Diagnostics.XmlWriterTraceListener" initializeData="c:\temp\WebWCFDataService.svclog" />
</listeners>
</source>
</sources>
</system.diagnostics>
... and opening using the Microsoft Service Trace Viewer, I see two idential warnings:
Configuration evaluation context not found.
<E2ETraceEvent xmlns="http://schemas.microsoft.com/2004/06/E2ETraceEvent">
<System xmlns="http://schemas.microsoft.com/2004/06/windows/eventlog/system">
<EventID>524312</EventID>
<Type>3</Type>
<SubType Name="Warning">0</SubType>
<Level>4</Level>
<TimeCreated SystemTime="2012-04-03T14:50:11.8355955Z" />
<Source Name="System.ServiceModel" />
<Correlation ActivityID="{66f1a241-2613-43dd-be0c-341149e37d30}" />
<Execution ProcessName="WebDev.WebServer40" ProcessID="5176" ThreadID="10" />
<Channel />
<Computer>MyComputer</Computer>
</System>
<ApplicationData>
<TraceData>
<DataItem>
<TraceRecord xmlns="http://schemas.microsoft.com/2004/10/E2ETraceEvent/TraceRecord" Severity="Warning">
<TraceIdentifier>http://msdn.microsoft.com/en-US/library/System.ServiceModel.EvaluationContextNotFound.aspx</TraceIdentifier>
<Description>Configuration evaluation context not found.</Description>
<AppDomain>fd28c9cc-1-129779382115645955</AppDomain>
</TraceRecord>
</DataItem>
</TraceData>
</ApplicationData>
</E2ETraceEvent>
So why am I able to see data from the browser, but not when consumed in my app?
-- UPDATE --
I downloaded the Microsoft WCF Data Services October 2011 CTP which exposed DataServiceProtocolVersion.V3, created a new host and client and referenced Microsoft.Data.Services.Client (v4.99.2.0). Now getting the following error on the client when trying iterate in the foreach loop:
There is a type mismatch between the client and the service. Type
'ConsoleApplication1.WcfDataServiceOctCTP1.GetDataSproc_Result' is an
entity type, but the type in the response payload does not represent
an entity type. Please ensure that types defined on the client match
the data model of the service, or update the service reference on the
client.
I tried the same thing by referencing the actual entity - works fine, so same issue.
Recap: I want to create a high-performing WCF service DAL (data access layer) that returns strongly-typed stored procedures. I initially used a "WCF Data Services" project to accomplish this. It seems as though it has its limitations, and after reviewing performance metrics of different ORM's, I ended up using Dapper for the data access inside a basic WCF Service.
I first created the *.edmx model and created the POCO for my sproc.
Next, I created a base BaseRepository and MiscDataRepository:
namespace WcfDataService.Repositories
{
public abstract class BaseRepository
{
protected static void SetIdentity<T>(IDbConnection connection, Action<T> setId)
{
dynamic identity = connection.Query("SELECT ##IDENTITY AS Id").Single();
T newId = (T)identity.Id;
setId(newId);
}
protected static IDbConnection OpenConnection()
{
IDbConnection connection = new SqlConnection(WebConfigurationManager.ConnectionStrings["PrimaryDBConnectionString"].ConnectionString);
connection.Open();
return connection;
}
}
}
namespace WcfDataService.Repositories
{
public class MiscDataRepository : BaseRepository
{
public IEnumerable<GetData_Result> SelectAllData()
{
using (IDbConnection connection = OpenConnection())
{
var theData = connection.Query<GetData_Result>("sprocs_GetData",
commandType: CommandType.StoredProcedure);
return theData;
}
}
}
}
The service class:
namespace WcfDataService
{
public class Service1 : IService1
{
private MiscDataRepository miscDataRepository;
public Service1()
: this(new MiscDataRepository())
{
}
public Service1(MiscDataRepository miscDataRepository)
{
this.miscDataRepository = miscDataRepository;
}
public IEnumerable<GetData_Result> GetData()
{
return miscDataRepository.SelectAllData();
}
}
}
... and then created a simple console application to display the data:
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Service1Client client = new Service1Client();
IEnumerable<GetData_Result> result = client.GetData();
foreach (GetData_Result d in result)
{
Console.WriteLine(d.ID + "\t" + d.WHO_TYPE_NAME + "\t" + d.CREATED_DATE);
}
Console.Read();
}
}
}
I also accomplished this using PetaPOCO, which took much less time to setup than Dapper - a few lines of code:
namespace PetaPocoWcfDataService
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in code, svc and config file together.
public class Service1 : IService1
{
public IEnumerable<GetData_Result> GetData()
{
var databaseContext = new PetaPoco.Database("PrimaryDBContext"); // using PetaPOCO for data access
databaseContext.EnableAutoSelect = false; // use the sproc to create the select statement
return databaseContext.Query<GetData_Result>("exec sproc_GetData");
}
}
}
I like how quick and simple it was to setup PetaPOCO, but using the repository pattern with Dapper will scale much better for an enterprise project.
It was also quite simple to create complex objects directly from the EDMX - for any stored procedure, then consume them.
For example, I created complex type return type called ProfileDetailsByID_Result based on the sq_mobile_profile_get_by_id sproc.
public ProfileDetailsByID_Result GetAllProfileDetailsByID(int profileID)
{
using (IDbConnection connection = OpenConnection("DatabaseConnectionString"))
{
try
{
var profile = connection.Query<ProfileDetailsByID_Result>("sq_mobile_profile_get_by_id",
new { profileid = profileID },
commandType: CommandType.StoredProcedure).FirstOrDefault();
return profile;
}
catch (Exception ex)
{
ErrorLogging.Instance.Fatal(ex); // use singleton for logging
return null;
}
}
}
So using Dapper along with some EDMX entities seems to be a nice quick way to get things going. I may be mistaken, but I'm not sure why Microsoft didn't think this all the way through - no support for complex types with OData.
--- UPDATE ---
So I finally got a response from Microsoft, when I raised the issue over a month ago:
We have done research on this and we have found that the Odata client
library doesn’t support complex types. Therefore, I regret to inform
you that there is not much that we can do to solve it.
*Optional: In order to obtain a solution for this issue, you have to use a Xml to Linq kind of approach to get the complex types.
Thank you very much for your understanding in this matter. Please let
me know if you have any questions. If we can be of any further
assistance, please let us know.
Best regards,
Seems odd.
I am trying to incorporate 'EF Tracing Data Provider' into an existing MVC2 app using VS2010, .NET 4.0 in order to log all SQL commands. I have no interest at this time in the caching provider. I beleive I have followed all the steps listed in the blog posting. BLOG POST My project does compile without error, however when I attempt to run the project I get the following error:
'String cannot have zero length.' The error points to Extended_JCIMS_MVC2_EF_Entities.cs Line: 25
Line 25: public ExtendedJCIMS_DevEntities(string connectionString)
Line 26: :base(EntityConnectionWrapperUtils.CreateEntityConnectionWithWrappers(
I am unable to determine what is causing this error. I assume the error is referring to the connection string from the Web.Config file. It does not like the 'connectionString' variable. I'm obviously doing something worng. I would appreciate a push in the right direction.
The relevant bits are as follows:
Web.config
--------------------------------------------------------------------------
<add name="JCIMS_DevEntities"
connectionString="metadata=res://*/;provider=System.Data.SqlClient;provider connection string="Data Source=MyServer;Initial Catalog=MyDatabase;User ID=MyUser;Password=myPassWord;MultipleActiveResultSets=True""
providerName="System.Data.EntityClient"/>
<system.data>
<DbProviderFactories>
<add name="EF Tracing Data Provider" invariant="EFTracingProvider" description="Tracing Provider Wrapper"
type="EFTracingProvider.EFTracingProviderFactory, EFTracingProvider, Version=1.0.0.0, Culture=neutral, PublicKeyToken=def642f226e0e59b" />
<add name="EF Generic Provider Wrapper" invariant="EFProviderWrapper" description="Generic Provider Wrapper"
type="EFProviderWrapperToolkit.EFProviderWrapperFactory, EFProviderWrapperToolkit, Version=1.0.0.0, Culture=neutral, PublicKeyToken=def642f226e0e59b" />
</DbProviderFactories>
</system.data>
Global.ascx
-----------------------------------------------------------------------
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
//EFTracingProviderConfiguration - LOG ALL Sql commands
EFTracingProviderConfiguration.LogToFile = Server.MapPath("~/JCIMS_MVC2_EF_SQL_Logfie.txt");
}
Extended_JCIMS_MVC2_EF_Entities.cs
--------------------------------------------------------------------------
namespace JCIMS_MVC2_EF.DomainModel
{
/// <summary>
/// Partial calss that Extends the EF Datacontext Class
/// </summary>
public partial class ExtendedJCIMS_DevEntities : JCIMS_DevEntities
{
private TextWriter logOutput;
public ExtendedJCIMS_DevEntities()
: this("name=JCIMS_DevEntities")
{
}
public ExtendedJCIMS_DevEntities(string connectionString)
: base(EntityConnectionWrapperUtils.CreateEntityConnectionWithWrappers(
connectionString,
"EFTracingProvider"
))
{
}
//... and more
}
}
SearchRepository.cs
------------------------------------------------------------------
public class SQLSearchRepository : ISearchRepository
{
//Database connection
private ExtendedJCIMS_DevEntities db = new ExtendedJCIMS_DevEntities(); // tracing version
public IEnumerable<SearchResults> ListAll(string strSearch, string chkSearch)
{
return (from s in db.Schools....
// and more...
}
Appreciate any assistance anyone can give me...
Have you debugged and confirmed that the connectionString passed into the ExtendedJCIMS_DevEntities method is not null or empty? That's what the error seems to indicate.
I have been trying to use the configurable provider model for handling my MEF imports and exports from MEF Contrib (link). I've read the Codeplex documentation and Code Junkie's blog post (link); however, I can't seem to get the container to create the parts. Where am I going wrong?
Program.cs
namespace MEFTest
{
class Program
{
static void Main(string[] args)
{
Program p = new Program();
p.Run();
}
// [ImportMany("command", typeof(IHelp))]
public IEnumerable<IHelp> Commands { get; set; }
void Run()
{
Compose();
foreach(IHelp cmd in Commands)
{
Console.WriteLine(cmd.HelpText);
}
Console.ReadKey();
}
void Compose()
{
var provider = new ConfigurableDefinitionProvider("mef.configuration");
var catalog = new DefinitionProviderPartCatalog<ConfigurableDefinitionProvider>(provider);
var container = new CompositionContainer(catalog);
container.ComposeParts(this);
}
}
}
TestCommand.cs
namespace MEFTest
{
//[Export("command", typeof(IHelp))]
public class TestCommand : IHelp
{
private string _helpText = "This is a test.";
public string CommandName
{
get { return "Test"; }
}
public string HelpText
{
get { return _helpText; }
}
}
}
App.Config section:
<mef.configuration>
<parts>
<part type="MEFTest.TestCommand, MEFTest">
<exports>
<export contract="IHelp" />
</exports>
</part>
<part type="MEFTest.Program, MEFTest">
<imports>
<import member="Commands" contract="IHelp" />
</imports>
</part>
</parts>
</mef.configuration>
I don't get any build errors and it runs fine if I switch to the typical attribute-based system that is part of the MEF core (with the appropriate catalog too). Program.Commands is always NULL in the above example. I tried to just use a singular property instead of a collection and get the same results.
When I debug I can get the provider.Parts collection so I know it's accessing the configuration information correctly; however, I get an InvalidOperationException whenever I debug and try to drill into catalog.Parts.
Anyone have any experience as to where I'm going wrong here?
As documented here, you also need this in your config file:
<configSections>
<section
name="mef.configuration"
type="MefContrib.Models.Provider.Definitions.Configurable.PartCatalogConfigurationSection, MefContrib.Models.Provider" />
</configSections>
If you already have that, then it might be interesting to show us the stack trace of the InvalidOperationException that you get when accessing provider.Parts.
I had the same problems and could not get it to work, but here are some details:
It seems that ComposeParts() does not work as expected (at least in the version I used) because it uses static methods, based on Reflection to find all required Imports (so it seems that this part cannot be changed from outside of MEF). Unfortunately we want to use xml configuration and not the MEF attributes.
It works if you add [Import] attributes to the members of the class you you use with ComposeParts(). In your case this would be "Programm". In this case all exports defined in the configuration file will be found.
I could not find any documentation or examples on the MEF Contrib page relating to that problem. Also there is no unittest in the MEF contrib projekt that uses ComposeParts().
A workaround would be to use container.GetExportedValues() to retrieve the values, but in this case you have to set the classes members manually.
Hope that helps.