Stitching Linq with if blocks
It's not bad already (save for the weird formatting of parameters, what's with commas at the beginning of the line? : ) But that's a matter of taste, and beyond the point).

You could return to the trick you used in your previous implementation to avoid breaking the chain and get rid of value reassignments by pushing includeBlanks into the predicate, like so:

values = values.Where(v =&gt; includeBlanks || v != string.Empty);


We've cut on verbosity, but it's debatable to me whether it improves readability.

It's harder to achieve the same thing for Distinct, although you could pull it through if you added a helper extension:

private static IEnumerable&lt;T&gt; If(this IEnumerable&lt;T&gt; enumerable, bool condition, IEnumerable&lt;T&gt; ifMet)
{
    return condition ? ifMet : enumerable;
}


Then you could turn all of it into a single statement:

return String.Join(
    between,
    values
        .Where(v =&gt; includeBlanks || v != string.Empty)
        .If(excludeDuplicates, values.Distinct())
        .Select(v =&gt; begin + v + end); 


Is it worth it, or over-engineered? This is subjective and a matter of taste. Some find verbosity more readable, others prefer terseness/expressiveness. 

I would let both solutions slide in a peer review, although creating a single-use extension method (If) looks like a minor code smell.

Another way to avoid repetitive overwriting of values, which you're uncomfortable with, would be to introduce temporary variables:

var blanksHandled = includeBlanks ? values : values.Where(v =&gt; v != String.Empty);
var duplicatesHandled = excludeDuplicates ? blanksHandled.Distinct() : blanksHandled;
var withAffixes = duplicatesHandled.Select(v =&gt; begin + v + end);


We're not overwriting values now, but when I look at it, I feel it sacrificed too much readability just for that, and what's worse, it got error-prone in process: you now have to remember to always use the last variable so as not to skip a step. 

If another parameter was to be added, there's a risk of a bug slipping in:

var blanksHandled = includeBlanks ? values : values.Where(v =&gt; v != String.Empty);
var duplicatesHandled = excludeDuplicates ? blanksHandled.Distinct() : blanksHandled;
// oops! will everyone spot right away what went wrong here?
var dirtyWordsHandled = safeMode ? blanksHandled.Except(dirtyWords) : blanksHandled;
var withAffixes = duplicatesHandled.Select(v =&gt; begin + v + end);


The last trick I can think of would be to convert these conditionals into Func&lt;IEnumerable&lt;T&gt;, IEnumerable&lt;T&gt;&gt; instances, and pass them to the LINQ chain.

I haven't got a C# IDE on this computer, so this code could be syntactically incorrect, but you get the idea:

Func&lt;IEnumerable&lt;String&gt;, IEnumerable&lt;String&gt;&gt; handleDuplicates = (entries) =&gt; excludeDuplicates ? entries.Distinct() : entries;
// etc.


And use them as selectors:

values
   .Select(handleBlanks)
   .Select(handleDuplicates)
   // ...


Again, is it worth it? Sometimes the clever thing is not to be too clever, and keeping it simple beats trying to make it pretty.