Issue with SubSonic and Multiple Providers - subsonic

I have two Subsonic-generated Data Access Layers for 2 different databases that I use in one project and so I have the following in my web.config:
<SubSonicService>
<providers>
<add name="BLLDB" type="SubSonic.SqlDataProvider, SubSonic" connectionStringName="BLLDB" generatedNamespace="BLLDB" useSPs="true" />
<add name="BLLDB2" type="SubSonic.SqlDataProvider, SubSonic" connectionStringName="BLLDB2" generatedNamespace="BLLDB2" useSPs="true" />
</providers>
</SubSonicService>
yet, anytime I call the code for either DAL it always ends up using the second data Provider listed ("BLLDB2"), and so gives an error like "Invalid object name 'dbo.Users'" when it should be reading from "BLLDB" (despite me explicitly specifying "BLLDB" in the Select())
e.g. check the following code for the "BLLDB" DAL:
Dim mySelect As New
SubSonic.Select(Databases.BLLDB)
mySelect.From(Of User)()
"mySelect.ProviderName" returns a string value: "BLLDB2"
whereas "Databases.BLLDB" returns a string value: "BLLDB"
what gives??

One of your provider is failing. Subsonic is not good about telling you why and where its failing.
I usually debug in couple of ways.
Use only one provider at a time and comment the other one. Check if you are able to see the namespace. If both of them load fine, then you atleast know its not the database.
Check if any of you tables start with -, _, or numbers. This can cause it fail as well.
Let me know how it goes.

You can specify which provider is default by using:
< SubSonicService defaultProvider="BLLDB" >

I am new to Subsonic (using version 2.2 with C#). I spent a lot of time trying to get the same configuration as Stimpy to work. I think I figured it out - my solution below. If this is correct, it would be great to add this information to the Select Queries documentation. so others can resolve this multiple data provider issue earlier.
Here's the web.config
<SubSonicService enableTrace="false" templateDirectory="">
<providers>
<clear/>
<add name="DB1" type="SubSonic.SqlDataProvider, SubSonic" connectionStringName="DB1" excludeProcedureList="*" generatedNamespace="DB1" includeTableList="TableA" tableBaseClass="RepositoryRecord"/>
<add name="DB2" type="SubSonic.SqlDataProvider, SubSonic" connectionStringName="DB2" excludeProcedureList="*" generatedNamespace="DB2" includeTableList="TableB,TableC" tableBaseClass="RepositoryRecord"/>
</providers>
Here's the statement that doesn't work (taken from the Select Queries documentation examples). SQL Server can't find "TableA" because it's looking for it in DB2 instead of DB1:
DB1.TableA doesntWork = new Select().From<DB1.TableA>().
Where("idCol").IsEqualTo(1).ExecuteSingle<DB1.TableA>();
(My assumption had been that the dataProvider for each table would have been generated as a property of the table class).
Here's the modification to make this work:
Select mySelect = DB1.DB.Select();
DB1.TableA works = mySelect.From<DB1.TableA>().
Where("idCol").IsEqualTo(1).ExecuteSingle<DB1.TableA>();
OR, this also works:
DB1.TableA worksAlso = new Select(DataService.GetInstance(Databases.DB1)).From<DB1.TableA>().
Where("idCol").IsEqualTo(1).ExecuteSingle<DB1.TableA>();
It seems that if you have a single dataProvider OR you specify in the SubSonicService config. that the default dataProvider is the one you're trying to use, everything works fine:
<SubSonicService enableTrace="false" defaultProvider="DB1" templateDirectory="">
But, if you leave out the "defaultProvider", it defaults to the last one in the providers list (in this case, DB2)
Another important piece of information for the multiple DAL case - if you generate the code into different folders for each provider, be sure to “include” in your project only ONE of the "AllStructs.cs" files that automatically gets generated into each folder (otherwise, compile errors).
FYI: kudos to the developers of this open source alternative to Codesmith. So far (other than this issue), it's been easy to get started and make it work (especially with SubStage). Also, I think it will end up being a lighter weight, cost-effective solution for my clients. Thank you!

I am using subsonic 2.2 substage. You need to change the namespaces for multiple providers respectfully.
One important thing. It will generate multiple "AllStructs.vb" files. It will be repeated by code automatically. But you need to add single allstructs.vb another just delete and it will work 1000%.
here would be the configuration settings at web config file.
<connectionStrings>
<add name="aspnetdb" connectionString="Data Source=(local); Database=aspnetdb; Integrated Security=true;"/>
<add name="office" connectionString="Data Source=(local); Database=office; Integrated Security=true;"/>
</connectionStrings>
<SubSonicService defaultProvider="aspnetdb" enableTrace="false" templateDirectory="">
<providers>
<clear/>
<add name="aspnetdb" type="SubSonic.SqlDataProvider, SubSonic" connectionStringName="aspnetdb"/>
<add name="office" type="SubSonic.SqlDataProvider, SubSonic" connectionStringName="office"/>
</providers>
</SubSonicService>

Hi all and thanks for the replies... Rob if I specify the default provider of "BLLDB" this ends up doing the same thing, but for BLLDB instead of BLLDB2
i.e. it only reads from BLLDB and not BLLDB2
CodeToGlory, I'm using the latest dlls and usually have no issues running SubSonic until I came across this prob.
Would it be possible for you to post up the web.config entries you use for subsonic where you have both providers working please?
Thanks a million!
P.S. It's also rather odd that when I specify which data provider to use directly in my Select() function:
e.g.
Dim mySelect As New SubSonic.Select(Databases.BLLDB)
mySelect.From(Of User)()
and then I do:
"mySelect.ProviderName", this returns a string value: "BLLDB2" (not correct)
whereas when I output the value for "Databases.BLLDB" this returns a string value: "BLLDB" (correct)
This could actually be the key to the problem...

Just answering my own question here .. it seems to indeed be NOT possible to use multiple providers when working through VB.NET.
This possibly only works in C# (as CodeToGlory mentioned), as I've tested several different scenarios from scratch and cannot get 2 Subsonic-generated DALs to work side-by-side
Will have to hack my own one together for one of them so.. Cheers for the advice though!

Related

Creating dynamic log files via Log4Net by process ID & date without rename policy

I have been scratching around Stack and the net for a solution to my particular use case but has yet have not found one.
Log4Net 1.2.10
IIS 6.1
.NET application using CastleCore
My requirement is to create a unique file name based on process id per hour with process id, date and hour in the filename. Although if the process Id were to change within that hour then create a new file name based on that process id and date/hour.
I have a service running on a web farm in IIS, this has 4 worker processes running simultaneously, 2 app pools 2 process per pool. So 4 log files being written too simultaneously.
My current config (below) appears to work upto a point. The files get created and are logged too simultaneously, great! The logging is quite heavy in that over the course of an hour it will log around
200MB per process id.
During the course of the hour one of the files out of the two simply stops writing. I have set Minimal lock and different process id's which should prevent any deadlocks, race conditions or collisions.
My current config is below
<appender name="WSG_file_appender" type="WSG.Logger.LogAppender,WSG.Logger">
<file type="log4net.Util.PatternString" value="../../WSG/IWSGServices-[%processid]" />
<datePattern value="-dd.MM.yyyy-HH'.log'" />
<staticLogFileName value="false"/>
<rollingStyle value="Date" />
<appendToFile value="true" />
<maximumFileSize value="500MB" />
<maxSizeRollBackups value="50" />
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="[%d] [%t] %-5p [%m]%n" />
</layout>
The format of the log that is generated is:
IWSGServices[8977]-23.03.15.14.log
This is what I want, in the above example that is the log for process ID 8977 for 1400 hours. At 1500 new logs gets generated for each process id in use and the new hour stamp.
When the logging stops in log4net debug mode I get this error many times:
log4net:ERROR [LogAppender] Failed to write [].
System.ArgumentOutOfRangeException: Count cannot be less than zero.
Parameter name: count
at System.String.CopyTo(Int32 sourceIndex, Char[] destination, Int32 destinationIndex, Int32 count)
at System.IO.StreamWriter.Write(String value)
at log4net.Util.QuietTextWriter.Write(String value)
I have not found any similar cases of this error within log4net so use cases are limited. I suspect there is some I/O issue or log4net (at least this older version) is not capable of fulfilling my use case. However I am not convinced latest versions will be either. I have not upgraded log4net yet due to reported issues with later versions and Castle Core implementations.
Setting StaticLogFileName=true results in filenames being created without the date stamp i.e WSGServices[8699], and then on the hour gets renamed to IWSGServices[8977]-23.03.15.14.log for example. This is not what I want as for this use case I do not want files to get renamed as I have a log reader which sees this as a new file and parses it again.
I have tried a large number of combinations including with and without locking models, Rolling styles, datepatterns and the config above seems to be the closest I have come. It's possible this config will work if I roll per minute but this will result in over 3000 log files per day which is not practical.
I'd like to achieve this under the current version of log4net I am using, however if I patch to 2.11 there is a setting of PreserveLogFileNameExtension parameter although the file will still get renamed but just not after the extension.
One suggestion I looked at was setting the IIS pool setting Disable Overlap Recycle to false but this didn't make any difference as would only come into play on recycles of the app pool.
Another alternative is too log both processes form each app pool to a single log file although due to the amount of writes I think this solution would not work without further process collisions.
Any help appreciated in case I have missed something or if anyone has used this in current or later log4net versions.

Disable StyleCop Rule with VS2012 Express

I am using Visual Studio 2012 Express and therefore don't have access to the integration for the regular version of VS. I have used the MSBuild to integrate StyleCop and the rules show up as Warnings. I want to be able to disable rules. The Disabling StyleCop rules post shows that this is possible but I can't make sense of the answer which suggests to edit the Settings.StyleCop file. However, I don't understand what is required to be added to this file to disable a rule.
If I wanted to disable rule SA1649 for instance how would I update the following file?
<StyleCopSettings Version="4.3">
<GlobalSettings>
<CollectionProperty Name="DeprecatedWords">
<Value>preprocessor,pre-processor</Value>
<Value>shortlived,short-lived</Value>
</CollectionProperty>
</GlobalSettings>
<Parsers>
<Parser ParserId="StyleCop.CSharp.CsParser">
<ParserSettings>
<CollectionProperty Name="GeneratedFileFilters">
<Value>\.g\.cs$</Value>
<Value>\.generated\.cs$</Value>
<Value>\.g\.i\.cs$</Value>
</CollectionProperty>
</ParserSettings>
</Parser>
</Parsers>
<Analyzers>
<Analyzer AnalyzerId="StyleCop.CSharp.NamingRules">
<AnalyzerSettings>
<CollectionProperty Name="Hungarian">
<Value>as</Value>
<Value>do</Value>
<Value>id</Value>
<Value>if</Value>
<Value>in</Value>
<Value>is</Value>
<Value>my</Value>
<Value>no</Value>
<Value>on</Value>
<Value>to</Value>
<Value>ui</Value>
</CollectionProperty>
</AnalyzerSettings>
</Analyzer>
</Analyzers>
</StyleCopSettings>
Note: I am using version 4.7 even though the default settings file shows 4.3
I found the following documentation to edit a stylecop rule in the XML
The XML code snippet is below.
<StyleCopSettings Version="4.3">
<Analyzers>
<Analyzer AnalyzerId="Microsoft.StyleCop.CSharp.LayoutRules">
<Rules>
<Rule Name="StatementMustNotBeOnSingleLine">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementMustNotBeOnSingleLine">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
</Rules>
<AnalyzerSettings />
</Analyzer>
</Analyzers>
</StyleCopSettings>
In addition, I also found out that you can drag the Settings.Sytlecop file onto the StyleCopSettingsEditor.exe which presents a GUI for enabling and disabling the rules.
Paste the below code in notepad and save as settings.StyleCop and place it in solution folder and build
<StyleCopSettings Version="105">
<GlobalSettings>
<BooleanProperty Name="RulesEnabledByDefault">False</BooleanProperty>
</GlobalSettings>
</StyleCopSettings>

IIS web.config, any other % symbols apart from %s?

Regarding the scriptProcessor in the handlers section of IIS's web.config, are there any % symbols apart from %s (which seems to represent the requested filename)? For example, is %a a recognised macro/symbol? If there are others besides %s, where are they described?
Your question is a bit unclear, so I had to make a number of assumptions in order to answer it. Please let me know if I got anything wrong.
From the documentation:
Script Processor
Optional string attribute.
Specifies the physical path of the ISAPI extension .dll file or Common Gateway Interface (CGI) .exe file that processes the request.
The scriptProcessor attribute is required only for script map handler mappings. When you map a handler to an ISAPI extension, you must specify ISAPIModule for the modules attribute. When you map a handler to a CGI file, you must specify CGIModule for the modules attribute.
From the documentation, we don't see any mention of format strings at all. If there were format strings, what would you replace them with? There's no clear answer based on the XML. Perhaps you're mistaking an environment variable for a format string. Or your particular configuration setup has some post processing that's ran on it before it's pushed live.
If we are actually talking about environment variables, then you can view them by issuing Win+Break to bring up system settings, go to advanced, then open up environment variables. You may also define your own. To use any environment variable you can use %variablename% as you would in a standard .bat file.
EDIT: Upon greater research, I've found the following. %s will give you the script name, then %s again will give you the parameters foo=bar. This feature isn't advertised (that I can find) in any official IIS documentation. I strongly suspect that it's considered a deprecated feature. And they're pushing hard to make ISAPI the norm.
Because of how it's structured (ie like a standard format string) I suspect that trying other common format strings (%d %c %f) might yield you something interesting, but probably not. It looks like this was a very specific solution to a very specific problem.
It's not strictly related to your question but I post these 2 links as they are in some way connected and could be useful.
I've found how to use "#" and "$" to transform Web.Config, but I've found nothing on "%" that's not strictly related to environment variables.
First link: "#"
This first link explains the use of xdt:Transform and xdt:Locator attributes that you can use in Web.config transform files:
http://msdn.microsoft.com/en-us/library/dd465326.aspx
This example is an interesting use of Web.Config transformation using Conditions with "#":
<configuration xmlns:xdt="...">
<connectionStrings>
<add name="AWLT" connectionString="newstring"
providerName="newprovider"
xdt:Transform="Replace"
xdt:Locator="Condition(#name='oldname'
or #providerName='oldprovider')" />
</connectionStrings>
</configuration>
Second link: "$"
This second link shows how to use "$" to transform Web.Config avoiding the boring procedure to manually comment/uncomment Web.Config parts when deploying or testing in different servers:
http://andrewtwest.com/2010/02/25/using-web-config-transformations-in-web-site-projects/
An extract of the link, showing how to use MSBuild to transform Web.Config files starting from a Web Application project file:
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<OutputPath>bin\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<OutputPath>bin\</OutputPath>
</PropertyGroup>

Dynamics CRM 2011

I am new to Dynamics CRM 2011 Online. I am try to generate the data context class using CrmSvcUtil.exe
This is my command:
CrmSvcUtil.exe /out:E:\OrgXrm.cs
/url:https://mdtestuser.api.crm5.dynamics.com/XRMServices/2011/Organization.svc
/username:MDTest#MDTestUser.onmicrosoft.com /password:Password
But its giving an error:
Exiting program with exception: An error occurred when verifying
security for th e message. Enable tracing and view the trace files for
more information. CrmSvcUtil.exe Error: 0 : Exiting program with exit
code 2 due to exception : Sy stem.ServiceModel.FaultException: An
error occurred when verifying security for the message.
I was researching another issue when I ran across a post in the Microsoft forums that may help. I remembered this question so I thought I would post another answer as this one had a positive resolution.
Quote:
I have dealt with this one before. Verify the Time and Date settings (including timezones) are set correctly on both the server and your client machine. It seems that if the two machines are out of sync by more than a minute or two it will cause this problem.
On my client machine I had to restart Visual Studio also for some reason after I set the server clock to get it to connect up properly.
http://social.microsoft.com/Forums/en-US/0ad9a5ee-dcce-4146-a1e6-20eafdccff46/crmsvcutil-error-an-error-occurred-when-verifying-security-for-the-message?forum=crmdevelopment
To fully understand your error, you should use config file with enable tracing, here is an example of config file:
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="servicecontextname" value="XrmServiceContext"/>
<add key="codecustomization" value="Microsoft.Xrm.Client.CodeGeneration.CodeCustomization, Microsoft.Xrm.Client.CodeGeneration"/>
<add key="username" value="domain\user"/>
<add key="password" value="password"/>
<add key="out" value="XrmEntitiesReference.cs" />
</appSettings>
<system.diagnostics>
<trace autoflush="false" indentsize="4">
<listeners>
<add name="configConsoleListener" type="System.Diagnostics.ConsoleTraceListener">
<filter type="System.Diagnostics.EventTypeFilter" initializeData="Error" />
</add>
</listeners>
</trace>
</system.diagnostics>
</configuration>
check out example from here:
http://www.resultondemand.nl/support/sdk/06abab26-40fc-4b85-9a2a-5e68903ea138.htm
JIC somebody get the same error.
I made the connection and I were able to generate the context from CRM online. The unique difference is in the URL, I have the next:
https://architecture2.api.crm.dynamics.com/XRMServices/2011/Organization.svc
You see this say crm not crm5 but that depends on your organization, to get the rigth one:
Open your organization then Settings->Customizations->Developer Resources->Organization data service
My command line to execute CrmSvcUtil.exe is:
CrmSvcUtil.exe
/url:"https://architecture2.api.crm.dynamics.com/XRMServices/2011/Organization.svc"
/out:"E:\Context.cs"
/username:MyUser#architecture2.onmicrosoft.com
/password:Password
Something else the account should have the required permissions, my account has System Administrator role.
I realize this is a long-shot, but has your password changed recently?
With a command string like this, a lot of people use .bat files to automate the process.
I dislike using passwords in .bat files because:
They are not secure (obvious, I know)
Maintenance. Every time you update your password, you would have to remember to update every script. Or painfully troubleshoot every failure and finally remember that the password was embedded.
To mitigate this I use SET with a /P parameter to prompt for a password during .bat file execution.
Not perfect, but a lot better than hard coding a password.
Here is an example using the command string you supplied:
rem ----- begin script -----
SET /P pwd=Password:
CrmSvcUtil.exe /out:E:\OrgXrm.cs /url:https://mdtestuser.api.crm5.dynamics.com/XRMServices/2011/Organization.svc
/username:MDTest#MDTestUser.onmicrosoft.com /password:%pwd%
CLS
SET pwd=.
rem ----- end script -----
In this example the SET /P tells the command processor to set an environment variable and prompt for the input.
“pwd” is the environment variable being set.
“%pwd%” is the actual use of the environment variable.
“Password:” is the prompt string that will be displayed when the .bat file is run.
“CLS” clears the screen.
“pwd=.” sets the environment variable to “.” so the password is not left in the environment.
You can ignore the lines beginning with “rem” as they are simply remarks.
The “not perfect” part of the solution is that your password is visible as you type. However by clearing the screen immediately following the prompt it is cleared from the screen right away. There are other ways to prevent the password from being visible as you type, however I think they are vastly over complicated or require downloading some additional bits. The idea of using a .bat file is that it is quick and easily updatable ergo low maintenance.
The SET /P works well in my case as no one is looking over my shoulder whenever I need to refresh my file, and there is virtually no maintenance once the .bat file is written.

How do I only keep the most recent n entries in a log4net sql table?

I am using log4net to log to a sql table. I'd like to be able to either only keep the most recent n days, or the most recent n entries in the table. Is this possible with log4net?
Log4net do not have this capability built-in. But such a task is probably best placed as a job ,e.g. in SSIS (if you're running MS SQL Server) or similar tools.
I figured it out, for the commandText for the AdoNetAppender I set the command text to:
<commandText value="INSERT INTO Log ([Date],[Thread],[Level],[Logger],[Message],[Exception]) VALUES (#log_date, #thread, #log_level, #logger, #message, #exception); DELETE FROM [Log] WHERE [Date] < DATEADD(dd, -28, GETDATE())" />
It feels hacky, but it works. I'll post here if I find a neater solution.
I know I'm late to the party... but looking at ilivewithian's solution I would agree with Peter Lillevold's observation that having it cause additional load in the logging process is undesirable.
Wouldn't it also be possible to use a trigger in the database to auto-delete the older items? Sure, you would need a DB that supports triggers, but it seems like most modern ones (including open source ones like SQLite and PostgreSQL) do.

Resources