Showing posts with label C#. Show all posts
Showing posts with label C#. Show all posts

Monday, January 7, 2013

Null MessageBodyMember for WCF Stream Response

If you are using a WCF MessageContract that contains a MessageBodyMember of type Stream, as shown below, the Stream can never be null.

[MessageContract(WrapperNamespace = "Learnsomething.com/Internal/DataContracts/Responses/Certificates")]
public class CreateCertificateResponse : BaseResponseMessageContract, IDisposable
{

    [MessageHeader(Namespace = "Learnsomething.com/Internal/DataContracts/Responses/Certificates")]
    public long FileLength { get; set; }

    [MessageBodyMember(Order = 1, Namespace = "Learnsomething.com/Internal/DataContracts/Responses/Certificates")]
    public Stream CertificatePDF { get; set; }

    public void Dispose()
    {
        if (this.CertificatePDF != null)
        {
            this.CertificatePDF.Dispose();
            this.CertificatePDF = null;
        }
    }
}

If it is null when the response is sent back, then the connection will be closed improperly with a The socket connection was aborted error message.

If you must support a null Stream in the response, you can make use of the System.IO.Stream.Null value. That object is internal, called NullStream and inherits from Stream.

Links

Thursday, June 14, 2012

Working around RavenDB and Safe-By-Default

I have seen these questions from time to time.
"How can I get all of the documents in RavenDB?"
"How can I force RavenDB to return more documents that the "safe-by-default" limits?"
The questions above usually stem from someone needing to work around the "safe-by-default" protection due to some sort of special circumstance. So if you find yourself needing these techniques more often than not, then you are doing it wrong.

You can change the RavenDB configuration by increasing the default PageSize, but that is a global change. Instead you need to do two things.
  1. Ensure that you start a new DocumentSession when you reach the  MaxNumberOfRequestsPerSession limit.
  2. Make sure you page the query with respect to the RavenDB PageSize (which is 1024 by default).
The RavenDB paging mechanism will not override the configured maximum number of items allowed per page. So if you try to Take() more than the configured limit, you will not get an error. Instead RavenDB's safe-by-default kicks in and will impose the configured page size on your results.

Below is an example that gets all document id values that match the predicate.

IDocumentSession session = null;
try
{
    session = MvcApplication.DocumentStore.OpenSession();

    List<string> ravenPageIds = null;
    const int RAVEN_MAX_PAGE_SIZE = 1024;
    int currentPageNumber = 0;

    do
    {
        List<string> tempRavenPageIds  = (from p in session.Query<Page>()
                                          where p.IsActive == true
                                          select p.Id)
                                          .Skip(currentPageNumber++ * RAVEN_MAX_PAGE_SIZE)
                                          .Take(RAVEN_MAX_PAGE_SIZE).ToList();

        ravenPageIds.AddRange(tempRavenPageIds);

        if (session.Advanced.NumberOfRequests >= session.Advanced.MaxNumberOfRequestsPerSession)
        {
            session.Dispose();
            session = MvcApplication.DocumentStore.OpenSession();
        }
    } while (tempRavenPageIds.Count == RAVEN_MAX_PAGE_SIZE);
}
finally
{
    session.Dispose();
}

We had code similar to this that needed to run when an MVC Application started (in order to build page routing table). But since then, we were able to refactor the code such that we no longer need to employ this technique. Rather than simply throw it away, perhaps you may find it useful.


Links


Friday, October 28, 2011

Classes, Structs and LLBLGen Pro

I just found an interesting bug that has trickled into some of our code.

Can you identify what is wrong with the following code (don’t cheat by reading below):
Guid? enrollmentId = (from e in metaData.Enrollment
                      where e.LearnerId == learnerId 
                      select e.Id).FirstOrDefault();

The problem comes from the way that FirstOrDefault() operates. In LLBLGen's case, that method will either take the first value, or it will set the default value if it does not find a match. This is where it is important to know what you are selecting. In this case, the query is selecting the e.Id, which is a Guid. A Guid can never be null because it is a struct and it is not a class.
Other things that are structs include: bool, int, short, long, byte, DateTime, KeyValuePair, etc...
If you are selecting a value that is a class, the default value will be NULL because classes are reference types.
If you are selecting a value that is a struct, the default value will never be NULL because structs are value types.
Side Note: The default value for a struct can be determined generically using the following (Where T is a type of struct):
T defaultValueForType = default(T);
So how do we select a struct using FirstOrDefault()?
You can work around this by selecting a class instead. The best way to do it is to use an Anonymous Type as shown below.
var enrollmentId = (from e in metaData.Enrollment
                    where e.LearnerId == learnerId 
                    select new { e.Id }).FirstOrDefault();

Anonymous Types are classes, therefore they can be null. By using an anonymous type in our query, the enrollmentId variable will be NULL if there are no records found.

Links